HNOI2016 Day2 T2 网络<树链剖分>
2016-05-16 21:01
567 查看
题意
分析
考虑树链剖分。用线段树搞,线段树上每个点开一个优先队列(大根对)。
每次有新的交互(u,v),就把不在(u,v)路径上的点加入一个v值。
查询时,就查这个点的top。
因为要删除,把优先队列换种写法,一个add队列,一个del队列,具体看代码。
应该是最好理解的做法了,但并不好打。
代码
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<cmath> #include<queue> using namespace std; const int maxn=100000+10; int n,m,q1[2*maxn],q2[2*maxn],q3[2*maxn]; //邻接表 struct Adjacency_list{ int tot=0; //总边数(从零开始计数,使得e的反向边为e^1) int first[maxn]; //该点连的第一条边(最晚加进来的一条边) struct edge{ int to,next; }e[maxn]; void init(int n){ //初始化0~n点的first for(int i=0;i<=n;i++) first[i]=-1; } void addedge(int u,int v){ //在u与v之间连一条无边权的无向边(即u->v,v->u) e[tot].to=v; e[tot].next=first[u]; first[u]=tot++; e[tot].to=u; e[tot].next=first[v]; first[v]=tot++; } }a; //线段树 struct Segment_tree{ priority_queue<int,vector<int>,less<int> > a[maxn*4],b[maxn*4]; //维护线段树每个点最大重要度,a维护加入,b维护删除 void Add(int u,int v) { //fprintf(stderr,"%d add %d\n",u,v); a[u].push(v);} void Del(int u,int v) { //fprintf(stderr,"%d del %d\n",u,v); b[u].push(v);} int Top(int u){ while(!b[u].empty()&&b[u].top()==a[u].top()) a[u].pop(),b[u].pop(); if(a[u].empty()) return -1; else return a[u].top(); } //把y1~y2的值加v(也可用来建树) int y1,y2,v; void update(int o,int l,int r){ int lc=o*2,rc=o*2+1; //左右儿子 int mid=(l+r)>>1; if(y1<=l&&y2>=r) Add(o,v); else{ if(y1<=mid) update(lc,l,mid); if(y2>mid) update(rc,mid+1,r); } } //把y1~y2的值删去v void erase(int o,int l,int r){ int lc=o*2,rc=o*2+1; //左右儿子 int mid=(l+r)>>1; if(y1<=l&&y2>=r) Del(o,v); //if(y1<=l&&y2>=r&&o==1&&v==0) y1=y1; else{ if(y1<=mid) erase(lc,l,mid); if(y2>mid) erase(rc,mid+1,r); } } //查询y1 int _max; void query(int o,int l,int r){ if(l==r){ _max=max(Top(o),_max); return; } else{ int lc=o*2,rc=o*2+1; //左右儿子 int mid=(l+r)>>1; _max=max(_max,Top(o)); if(y1>mid) query(rc,mid+1,r); else query(lc,l,mid); } } }l; //树链剖分 int dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],val[maxn],top[maxn]; //top最近的重链父节点 int num; void dfs1(int u,int f,int d){ dep[u]=d; siz[u]=1; son[u]=0; fa[u]=f; for(int i=a.first[u];i!=-1;i=a.e[i].next){ int v=a.e[i].to; if(v!=f){ dfs1(v,u,d+1); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u]=v; } } } void dfs2(int u,int tp){ top[u]=tp; id[u]=++num; if(son[u]) dfs2(son[u],tp); for(int i=a.first[u];i!=-1;i=a.e[i].next){ int v=a.e[i].to; if(v!=fa[u]&&v!=son[u]){ dfs2(v,v); } } } //************************************************************************************************************ int totp; struct line{ int l,r; }p[25]; bool operator < (const line& l1,const line& l2){ return l1.l<l2.l||(l1.l==l2.l&&l1.r<l2.r); } void find(int u,int v){ if(top[u]==top[v]) //属于同一条重链 { ++totp; p[totp].l=id[u]; p[totp].r=id[v]; if(p[totp].l>p[totp].r) swap(p[totp].l,p[totp].r); } else{ if(dep[top[u]]!=dep[top[v]]){ if(dep[top[u]]<dep[top[v]]) swap(u,v); ++totp; p[totp].r=id[u]; p[totp].l=id[top[u]]; find(fa[top[u]],v); } else{ ++totp; p[totp].r=id[u]; p[totp].l=id[top[u]]; ++totp; p[totp].r=id[v]; p[totp].l=id[top[v]]; find(fa[top[u]],fa[top[v]]); } } } void operation1(int u,int v,int w){ totp=0; find(u,v); sort(p+1,p+totp+1); p[0].r=0;p[totp+1].l=n+1; for(int i=0;i<=totp;i++){ l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=w; if(l.y1<=l.y2) l.update(1,1,n); } } void operation2(int t){ totp=0; find(q1[t],q2[t]); sort(p+1,p+totp+1); p[0].r=0;p[totp+1].l=n+1; for(int i=0;i<=totp;i++){ l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=q3[t]; if(l.y1<=l.y2) l.erase(1,1,n); } } int operation3(int x){ l._max=-1; l.y1=id[x]; l.query(1,1,n); return l._max; } //************************************************************************************************************ int main() { //freopen("network.in","r",stdin); //freopen("network.out","w",stdout); cin>>n>>m; a.init(n); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); a.addedge(u,v); } dfs1(1,0,1); dfs2(1,1); for(int i=1;i<=m;i++){ int start; scanf("%d",&start); //int xxxx=operation3(3); //printf("(1)------》%d\n",xxxx); if(start==0){ scanf("%d%d%d",&q1[i],&q2[i],&q3[i]); operation1(q1[i],q2[i],q3[i]); } else if(start==1){ int tt; scanf("%d",&tt); operation2(tt); } else{ int xx; scanf("%d",&xx); printf("%d\n",operation3(xx)); } } return 0; } /* 13 23 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 6 10 6 11 7 12 7 13 2 1 0 8 13 3 0 9 12 5 2 9 2 8 2 2 0 10 12 1 2 2 1 3 2 7 2 1 0 9 5 6 2 4 2 5 1 7 0 9 12 4 0 10 5 7 2 1 2 4 2 12 1 2 2 5 2 3 */