QTREE4

QTREE4

点分治

  题目链接:https://www.luogu.org/problemnew/show/P4115

  参考:http://www.cnblogs.com/yanshannan/p/9411098.html 

  

    首先观察此题每条边的长度-1000<=w<=1000

    而当0<=w<=1000的时候会有一个更优的nlogn解法

      线段树维护树的直径

      怎么维护?

      有一个结论:

        一颗树内,某些点构成的点集 形成的一个新树,该树的直径端点为x,y;

        现在新加入一个点z,形成新的点集构成的新树的直径端点为(x,y)或(x,z)或(y,z);

      于是用线段树维护一下就好,合并时用线段树两个儿子代表的树直径端点更新即可

   lca用dfs序+st表,单次查询O1

线段树维护的代码

  1 #include<iostream>
  2 #include<cstdio>
  3 using namespace std;
  4 const int M=100009;
  5 int n,m,num=0,id=0,sum;
  6 int head[M],fir[M],L[M<<1],pw[23],val[M],f[M<<1][23],dep[M];
  7 struct P{int to,ne,w;}e[M<<1];
  8 int ls[M<<2],rs[M<<2],len[M<<2];
  9 bool vis[M];
 10 int read(){
 11     int rex=0,f=1;char ch=getchar();
 12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 13     while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();}
 14     return rex*f;
 15 }
 16 void dfs(int u,int fa,int w){
 17     f[fir[u]=++id][0]=u;val[u]=w;dep[u]=dep[fa]+1;
 18     for(int i=head[u];i;i=e[i].ne){
 19         int v=e[i].to;
 20         if(v!=fa){dfs(v,u,w+e[i].w);f[++id][0]=u;}
 21     }
 22 }
 23 int Min(int x,int y){
 24     return dep[x]<dep[y]?x:y;
 25 }
 26 int ask(int l,int r){
 27     l=fir[l],r=fir[r];
 28     if(l>r)swap(l,r);
 29     int k=L[r-l+1];
 30     return Min(f[l][k],f[r-pw[k]+1][k]);
 31 }
 32 int dis(int u,int v){
 33     return val[u]+val[v]-2*val[ask(u,v)];
 34 }
 35 void merge(int a,int b,int c,int dist=0){
 36     if(ls[a]==0||ls[b]==0){
 37         ls[c]=ls[a]+ls[b];
 38         rs[c]=rs[a]+rs[b];
 39         len[c]=len[a]+len[b];
 40         return;
 41     }
 42     if(len[a]<len[b])swap(a,b);
 43     ls[c]=ls[a],rs[c]=rs[a],len[c]=len[a];
 44     dist=dis(ls[a],ls[b]);
 45     if(dist>len[c]){len[c]=dist;ls[c]=ls[a];rs[c]=ls[b];}
 46     dist=dis(ls[a],rs[b]);
 47     if(dist>len[c]){len[c]=dist;ls[c]=ls[a];rs[c]=rs[b];}
 48     dist=dis(rs[a],ls[b]);
 49     if(dist>len[c]){len[c]=dist;ls[c]=rs[a];rs[c]=ls[b];}
 50     dist=dis(rs[a],rs[b]);
 51     if(dist>len[c]){len[c]=dist;ls[c]=rs[a];rs[c]=rs[b];}
 52 }
 53 void build(int now,int l,int r){
 54     if(l==r){
 55         ls[now]=rs[now]=l;
 56         len[now]=0;
 57         return;
 58     }
 59     int mid=(l+r)>>1;
 60     build(now<<1,l,mid);
 61     build(now<<1|1,mid+1,r);
 62     merge(now<<1,now<<1|1,now);
 63 }
 64 void update(int now,int l,int r,int x){
 65     if(l==r){
 66         if(vis[x])ls[now]=rs[now]=len[now]=0;
 67         else ls[now]=rs[now]=x,len[now]=0;
 68         return;
 69     }
 70     int mid=(l+r)>>1;
 71     if(x<=mid)update(now<<1,l,mid,x);
 72     else update(now<<1|1,mid+1,r,x);
 73     merge(now<<1,now<<1|1,now);
 74 }
 75 int main(){
 76     n=read();
 77     for(int i=1,u,v,w;i<n;++i){
 78         u=read(),v=read(),w=read();
 79         e[++num]=(P){v,head[u],w};head[u]=num;
 80         e[++num]=(P){u,head[v],w};head[v]=num;
 81     }
 82     dfs(1,0,0);pw[0]=1;L[1]=0;
 83     for(int i=1;i<=19;++i)pw[i]=pw[i-1]<<1;
 84     for(int i=2;i<=id;++i)L[i]=L[i>>1]+1;
 85     for(int j=1;j<=19;++j){
 86         for(int i=1;i+pw[j]-1<=id;++i){
 87             f[i][j]=Min(f[i][j-1],f[i+pw[j-1]][j-1]);
 88         }
 89     }
 90     build(1,1,n);
 91     m=read();sum=n;
 92     for(int i=1;i<=m;++i){
 93         char c[5];
 94         scanf("%s",c);
 95         if(c[0]=='C'){
 96             int x=read();
 97             vis[x]^=1;
 98             update(1,1,n,x);
 99             if(vis[x])sum--;
100             else sum++;
101         }
102         else {
103             if(sum==0)printf("They have disappeared.\n");
104             else printf("%d\n",len[1]);
105         }
106     }
107     return 0;
108 }
View Code

 

    当然此题的w是可以<0的,所以树直径的结论就不满足了

    此时我们就需要用到另外一种算法:动态点分治(O(n log ^2 n))

    就是对分治树上的每个点开2个堆

      1:此子树白点到他父节点的距离大根堆 a

      2:此节点的每个儿子子树中的白点到该节点的最大值组成的大根堆 b

      1用来更新2,此时经过某个重心u的 两个白点最大距离 可以为    b[u]大根堆的   最大值和次大值之和

    最后再总的维护一个答案堆 ans 即可

    更新答案就分治树上往上走,顺便更新下经过节点的堆和答案堆即可

    这三种堆需要满足一种操作,pop(x);

      可以开个结构题,里面2个堆,插入堆和删除堆

      取堆顶时,插入堆堆顶和删除堆堆顶相同时,2个堆同时pop(),如果不同就return 插入堆.top();

    代码

      

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 using namespace std;
  5 const int M=100009;
  6 int n,m,num=0,id=0,sum=0;
  7 int head[M];
  8 int pw[23],L[M<<1],fir[M],val[M],dep[M],f[M<<1][23];
  9 struct P{int to,ne,w;}e[M<<1];
 10 int minn,rt,size,siz[M],ft[M];
 11 bool vis[M],co[M];
 12 struct Queue{
 13     priority_queue<int>s,t;int sz;
 14     inline void push(int x){s.push(x);sz++;}
 15     inline void pop(int x){t.push(x);sz--;}
 16     inline int top(){
 17         if(sz==0)return -1e9;
 18         while(!t.empty()&&s.top()==t.top())s.pop(),t.pop();
 19         return s.top();
 20     }
 21     inline int len(){
 22         if(sz<2)return 0;
 23         int x=top();pop(x);
 24         int y=top();push(x);
 25         return max(0,x+y);
 26     }
 27     inline void del(int k,int x){k==0?push(x):pop(x);}
 28 }a[M],b[M],ans;
 29 inline int read(){
 30     int rex=0,f=1;char ch=getchar();
 31     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 32     while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();}
 33     return rex*f;
 34 }
 35 void dfs(int u,int fa,int w){
 36     f[fir[u]=++id][0]=u;val[u]=w;dep[u]=dep[fa]+1;
 37     for(int i=head[u];i;i=e[i].ne){
 38         int v=e[i].to;
 39         if(v!=fa){dfs(v,u,w+e[i].w);f[++id][0]=u;}
 40     }
 41 }
 42 inline int Min(int x,int y){
 43     return dep[x]<dep[y]?x:y;
 44 }
 45 inline int ask(int l,int r){
 46     l=fir[l],r=fir[r];
 47     if(l>r)swap(l,r);
 48     int k=L[r-l+1];
 49     return Min(f[l][k],f[r-pw[k]+1][k]);
 50 }
 51 inline int dis(int u,int v){
 52     return val[u]+val[v]-2*val[ask(u,v)];
 53 }
 54 void getrt(int u,int fa){
 55     int ma=0;siz[u]=1;
 56     for(int i=head[u];i;i=e[i].ne){
 57         int v=e[i].to;if(v==fa||vis[v])continue;
 58         getrt(v,u);siz[u]+=siz[v];ma=max(ma,siz[v]);
 59     }
 60     ma=max(ma,size-siz[u]);
 61     if(minn>ma){minn=ma,rt=u;}
 62 }
 63 void DFS(int u,int fa,int now){
 64     a[now].push(dis(ft[now],u));
 65     for(int i=head[u];i;i=e[i].ne){
 66         int v=e[i].to;
 67         if(v!=fa&&!vis[v])DFS(v,u,now);
 68     }
 69 }
 70 void work(int u){
 71     if(ft[u])DFS(u,0,u);vis[u]=1;b[u].push(0);
 72     for(int i=head[u];i;i=e[i].ne){
 73         int v=e[i].to;if(vis[v])continue;
 74         minn=1e9,size=siz[u];
 75         getrt(v,0);ft[rt]=u;
 76         int la=rt;
 77         work(rt);b[u].push(a[la].top());
 78     }
 79     ans.push(b[u].len());
 80 }
 81 inline void change(int u){
 82     ans.pop(b[u].len());
 83     b[u].del(co[u],0);
 84     ans.push(b[u].len());
 85     for(int i=u;ft[i];i=ft[i]){
 86         int x=a[i].top();
 87         a[i].del(co[u],dis(ft[i],u));
 88         int y=a[i].top();
 89         if(x==y)continue;
 90         ans.pop(b[ft[i]].len());
 91         b[ft[i]].pop(x);
 92         b[ft[i]].push(y);
 93         ans.push(b[ft[i]].len());
 94     }
 95 }
 96 int main(){
 97     n=read();
 98     for(int i=1,u,v,w;i<n;++i){
 99         u=read(),v=read(),w=read();
100         e[++num]=(P){v,head[u],w};head[u]=num;
101         e[++num]=(P){u,head[v],w};head[v]=num;
102     }
103     dfs(1,0,0);pw[0]=1;L[1]=0;
104     for(int i=1;i<=19;++i)pw[i]=pw[i-1]<<1;
105     for(int i=2;i<=id;++i)L[i]=L[i>>1]+1;
106     for(int j=1;j<=19;++j){
107         for(int i=1;i+pw[j]-1<=id;++i){
108             f[i][j]=Min(f[i][j-1],f[i+pw[j-1]][j-1]);
109         }
110     }
111     minn=1e9,size=n;
112     getrt(1,0);
113     work(rt);
114     m=read();sum=n;
115     for(int i=1;i<=m;++i){
116         char c[5];
117         scanf("%s",c);
118         if(c[0]=='C'){
119             int x=read();
120             co[x]^=1;
121             change(x);
122             sum+=co[x]?-1:1;
123         }
124         else {
125             sum==0?printf("They have disappeared.\n")
126             :printf("%d\n",ans.top());
127         }
128     }
129     return 0;
130 }
View Code

 

 

posted @ 2018-11-26 23:20  sjie  阅读(358)  评论(0编辑  收藏  举报