zoukankan      html  css  js  c++  java
  • SPOJ2666 QTREE4

    我是萌萌的传送门

    我是另一个萌萌的传送门

    一道树分治……简直恶心死了……我在调代码的时候只想说:我*************************************************……

    昨天听ztc讲了讲树分治,下午心血来潮想写QTREE4……写的是边分治,然后调了一晚上没调出来,后来发现换一个点作根建树就A了(COGS数据弱……)……然而交到vjudge上还是WA,早上接着调结果还调不出来,一怒之下弃坑去写比较简单的动态树分治,感觉点分治挺好写嘛……然后就换用点分治重写QTREE4,调了老半天才调出来……然而vjudge上TLE了= =

    这题好像点分治边分治链分治都可以,然而点分治比边分治慢,这根本不科学……看别人写的有点分治也有边分治,然而我边分治实在调不动了……

    贴一发点分治的代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=100010;
      8 struct binary_heap{
      9     priority_queue<int>q1,q2;
     10     void push(int x){q1.push(x);}
     11     int top(){
     12         while(!q2.empty()&&q1.top()==q2.top()){
     13             q1.pop();
     14             q2.pop();
     15         }
     16         return q1.top();
     17     }
     18     int top2(){
     19         int fir=top();
     20         pop();
     21         int sec=top();
     22         push(fir);
     23         return sec;
     24     }
     25     void pop(){
     26         while(!q2.empty()&&q1.top()==q2.top()){
     27             q1.pop();
     28             q2.pop();
     29         }
     30         q1.pop();
     31     }
     32     void erase(int x){q2.push(x);}
     33     int size(){return (int)q1.size()-(int)q2.size();}
     34     bool empty(){return !size();}
     35 }heap,q[maxn],q1[maxn][20];
     36 void build(int,int,int,int);
     37 void dfs_getcenter(int,int,int&);
     38 void dfs_getdis(int,int,int);
     39 void modify(int);
     40 vector<int>G[maxn],W[maxn];
     41 int size[maxn]={0},son[maxn]={0};
     42 int depth[maxn]={0},p[maxn]={0},d[maxn][20],id[maxn][20];
     43 bool vis[maxn]={false},col[maxn]={false};
     44 int n,m,white,x,y,z;
     45 char c;
     46 int main(){
     47     freopen("QTREE4.in","r",stdin);
     48     freopen("QTREE4.out","w",stdout);
     49     scanf("%d",&n);
     50     white=n;
     51     for(int i=1;i<n;i++){
     52         scanf("%d%d%d",&x,&y,&z);
     53         G[x].push_back(y);
     54         W[x].push_back(z);
     55         G[y].push_back(x);
     56         W[y].push_back(z);
     57     }
     58     heap.push(0);
     59     build(1,0,n,0);
     60     scanf("%d",&m);
     61     while(m--){
     62         scanf(" %c",&c);
     63         if(c=='C'){
     64             scanf("%d",&x);
     65             modify(x);
     66         }
     67         else{
     68             if(!white)printf("They have disappeared.
    ");
     69             else if(white==1)printf("0
    ");
     70             else printf("%d
    ",heap.top());
     71         }
     72     }
     73     return 0;
     74 }
     75 void build(int x,int k,int s,int pr){
     76     int u=0;
     77     dfs_getcenter(x,s,u);
     78     vis[x=u]=true;
     79     p[x]=pr;
     80     depth[x]=k;
     81     q[x].push(0);
     82     if(s<=1)return;
     83     for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]){
     84         d[G[x][i]][k]=W[x][i];
     85         p[G[x][i]]=0;
     86         dfs_getdis(G[x][i],G[x][i],k);
     87         q[x].push(q1[G[x][i]][k].top());
     88     }
     89     heap.push(q[x].top()+q[x].top2());
     90     for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]])build(G[x][i],k+1,size[G[x][i]],x);
     91 }
     92 void dfs_getcenter(int x,int s,int &u){
     93     size[x]=1;
     94     son[x]=0;
     95     for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]&&G[x][i]!=p[x]){
     96         p[G[x][i]]=x;
     97         dfs_getcenter(G[x][i],s,u);
     98         size[x]+=size[G[x][i]];
     99         if(size[G[x][i]]>size[son[x]])son[x]=G[x][i];
    100     }
    101     if(!u||max(s-size[x],size[son[x]])<max(s-size[u],size[son[u]]))u=x;
    102 }
    103 void dfs_getdis(int x,int v,int k){
    104     q1[v][k].push(d[x][k]);
    105     size[x]=1;id[x][k]=v;
    106     for(int i=0;i<(int)G[x].size();i++)if(!vis[G[x][i]]&&G[x][i]!=p[x]){
    107         p[G[x][i]]=x;
    108         d[G[x][i]][k]=d[x][k]+W[x][i];
    109         dfs_getdis(G[x][i],v,k);
    110         size[x]+=size[G[x][i]];
    111     }
    112 }
    113 void modify(int x){
    114     col[x]^=true;
    115     if(col[x]){
    116         if(q[x].size()>1)heap.erase(q[x].top()+q[x].top2());
    117         q[x].erase(0);
    118         if(q[x].size()>1)heap.push(q[x].top()+q[x].top2());
    119         white--;
    120     }
    121     else{
    122         if(q[x].size()>1)heap.erase(q[x].top()+q[x].top2());
    123         q[x].push(0);
    124         if(q[x].size()>1)heap.push(q[x].top()+q[x].top2());
    125         white++;
    126     }
    127     for(int u=p[x],k=depth[x]-1;u;u=p[u],k--){
    128         if(col[x]){
    129             if(q[u].size()>1)heap.erase(q[u].top()+q[u].top2());
    130             q[u].erase(q1[id[x][k]][k].top());
    131             q1[id[x][k]][k].erase(d[x][k]);
    132             if(!q1[id[x][k]][k].empty())q[u].push(q1[id[x][k]][k].top());
    133             if(q[u].size()>1)heap.push(q[u].top()+q[u].top2());
    134         }
    135         else{
    136             if(q[u].size()>1)heap.erase(q[u].top()+q[u].top2());
    137             if(!q1[id[x][k]][k].empty())q[u].erase(q1[id[x][k]][k].top());
    138             q1[id[x][k]][k].push(d[x][k]);
    139             q[u].push(q1[id[x][k]][k].top());
    140             if(q[u].size()>1)heap.push(q[u].top()+q[u].top2());
    141         }
    142     }
    143 }
    144 /*
    145 SPOJ2666 QTREE4
    146 动态树分治,这次改用点分治。
    147 每个重心的子树存一个堆维护到重心最远的白点,每个重心也存一个堆维护子树的答案,
    148 重心的堆的前两大的元素就可以用来更新答案,把答案扔到一个全局堆里。
    149 翻转时跳点分治树并修改对应子树和重心的堆,修改时顺便更新一下全局堆,
    150 查询时O(1)取全局堆最大值即可。
    151 */
    View Code

    没调出来的边分治……也贴过来好了……

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=400010;
      8 struct edge{int to,w,prev;bool vis;edge():to(0),w(0),prev(0),vis(false){}}e[maxn<<1];//存新树的边,vis代表是否已被删除
      9 struct A{//大根堆,维护答案
     10     int x,d;
     11     A(int x,int d):x(x),d(d){}
     12     bool operator<(const A &a)const{return d<a.d;}
     13 };
     14 void dfs_prework(int);//预处理,添虚点
     15 void addedge(int,int,int);//在新树上添一条边
     16 void build(int,int,int);//对以x为根的子树建边分治树
     17 void dfs_getedge(int,int,int&);//找中心边
     18 void dfs_getdis(int,int,int,int);//求距离
     19 void modify(int);//翻转颜色
     20 int getans(int);//更新点x对应的堆并返回当前答案
     21 vector<int>G[maxn],W[maxn];//原树的边
     22 int last[maxn],len=0,size[maxn]={0},p[maxn]={0};//建边分治树用的辅助数组
     23 int eid[maxn],d[maxn][25],id[maxn][25],dir[maxn][25];//在深度为k的边分治树中的距离和左右,对应的点的编号
     24 priority_queue<A>heap,q[maxn][2];//全局堆和边分治树的每个点的堆
     25 int n,m,cnt,x,y,z,col[maxn]={0},white;//记一下每个点现在的颜色,0白1黑
     26 char c;
     27 int main(){
     28     freopen("QTREE4.in","r",stdin);
     29     freopen("QTREE4.out","w",stdout);
     30     memset(last,-1,sizeof(last));
     31     memset(eid,-1,sizeof(eid));
     32     scanf("%d",&n);
     33     cnt=white=n;
     34     for(int i=1;i<n;i++){
     35         scanf("%d%d%d",&x,&y,&z);
     36         G[x].push_back(y);
     37         W[x].push_back(z);
     38         G[y].push_back(x);
     39         W[y].push_back(z);
     40     }
     41     dfs_prework(1);//getchar();getchar();
     42     memset(p,0,sizeof(p));//printf("cnt=%d
    ",cnt);
     43     cnt=0;
     44     build(1,0,n);
     45     scanf("%d",&m);
     46     while(m--){
     47         scanf(" %c",&c);
     48         if(c=='C'){
     49             scanf("%d",&x);
     50             modify(x);
     51         }
     52         else{
     53             while(!heap.empty()&&getans(heap.top().x)!=heap.top().d){
     54                 //printf("heap.pop()=(%d,%d)
    ",heap.top().x,heap.top().d);
     55                 x=heap.top().x;
     56                 heap.pop();
     57                 if((z=getans(x))!=1<<31)heap.push(A(x,z));
     58             }
     59             //printf("heap.size()=%d
    ",heap.size());
     60             if(!white)printf("They have disappeared.
    ");
     61             else if(white==1)printf("0
    ");
     62             else printf("%d
    ",max(heap.top().d,0));
     63         }
     64     }
     65     return 0;
     66 }
     67 void dfs_prework(int x){//预处理,添虚点
     68     for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x]){
     69         p[G[x][i]]=x;
     70         dfs_prework(G[x][i]);
     71     }
     72     A y(0,0),z(0,0);
     73     queue<A>q;
     74     for(int i=0;i<(int)G[x].size();i++)if(G[x][i]!=p[x])q.push(A(G[x][i],W[x][i]));
     75     while((int)q.size()>2){
     76         y=q.front();q.pop();
     77         z=q.front();q.pop();
     78         cnt++;
     79         addedge(cnt,y.x,y.d);
     80         addedge(y.x,cnt,y.d);
     81         addedge(cnt,z.x,z.d);
     82         addedge(z.x,cnt,z.d);
     83         q.push(A(cnt,0));
     84     }
     85     while(!q.empty()){
     86         y=q.front();q.pop();
     87         addedge(x,y.x,y.d);
     88         addedge(y.x,x,y.d);
     89     }
     90 }
     91 void addedge(int x,int y,int z){//在新树上添一条边
     92     e[len].to=y;//printf("addedge(%d,%d,%d)
    ",x,y,z);
     93     e[len].w=z;
     94     e[len].prev=last[x];
     95     last[x]=len++;
     96 }
     97 void build(int x,int k,int s){//对以x为根的子树建边分治树
     98     if(s<=1)return;
     99     int rt=++cnt;//printf("
    ");printf("build(%d,%d,%d)
    ",x,k,s);
    100     dfs_getedge(x,s,eid[rt]);
    101     int u=e[eid[rt]^1].to,v=e[eid[rt]].to;//printf("id=%d u=%d v=%d w=%d
    ",eid[rt],u,v,e[eid[rt]].w);
    102     e[eid[rt]].vis=e[eid[rt]^1].vis=true;
    103     p[u]=p[v]=d[u][k]=d[v][k]=0;
    104     dfs_getdis(u,rt,k,0);
    105     dfs_getdis(v,rt,k,1);
    106     if(!q[rt][0].empty()&&!q[rt][1].empty()){
    107         //printf("top=(%d,%d) w=%d
    ",q[rt][0].top().d,q[rt][1].top().d,e[eid[rt]].w);
    108         //printf("heap.push(%d,%d)
    ",rt,q[rt][0].top().d+q[rt][1].top().d+e[eid[rt]].w);
    109         heap.push(A(rt,q[rt][0].top().d+q[rt][1].top().d+e[eid[rt]].w));
    110     }
    111     //else printf("EMPTY
    ");
    112     build(u,k+1,s-size[v]);
    113     build(v,k+1,size[v]);
    114 }
    115 void dfs_getedge(int x,int s,int &id){//找中心边
    116     size[x]=1;//printf("dfs_getedge(%d,%d)
    ",x,s);
    117     for(int i=last[x];i!=-1;i=e[i].prev)if(!e[i].vis&&e[i].to!=p[x]){//printf("i=%d
    ",i);
    118         p[e[i].to]=x;
    119         dfs_getedge(e[i].to,s,id);
    120         size[x]+=size[e[i].to];
    121         if(id==-1||max(size[e[i].to],s-size[e[i].to])<max(size[e[id].to],s-size[e[id].to]))id=i;
    122     }
    123 }
    124 void dfs_getdis(int x,int rt,int k,int c){//求距离,顺便完成对对应层id和dir的标号
    125     //printf("dfs_getdis(%d,%d,%d,%d)
    ",x,rt,k,c);
    126     if(x<=n){
    127         //printf("q[%d][%d].push(%d,%d)
    ",rt,c,x,d[x][k]);
    128         q[rt][c].push(A(x,d[x][k]));
    129     }
    130     id[x][k]=rt;dir[x][k]=c;
    131     for(int i=last[x];i!=-1;i=e[i].prev)if(!e[i].vis&&e[i].to!=p[x]){//printf("i=%d
    ",i);
    132         p[e[i].to]=x;
    133         d[e[i].to][k]=d[x][k]+e[i].w;
    134         dfs_getdis(e[i].to,rt,k,c);
    135     }
    136 }
    137 void modify(int x){//翻转颜色
    138     if(col[x])white++;
    139     else white--;
    140     col[x]^=1;
    141     for(int i=20;i>=0;i--)if(id[x][i]){//如果是0表示深度过大不存在
    142         getans(id[x][i]);
    143         if(!col[x]){//原为黑色,入堆
    144             if((q[id[x][i]][dir[x][i]].empty()||q[id[x][i]][dir[x][i]].top().d<d[x][i])&&!q[id[x][i]][dir[x][i]^1].empty()){
    145                 heap.push(A(id[x][i],d[x][i]+q[id[x][i]][dir[x][i]^1].top().d+e[eid[id[x][i]]].w));
    146                 //printf("heap.push(%d,%d)
    ",id[x][i],d[x][i]+q[id[x][i]][dir[x][i]^1].top().d+e[eid[id[x][i]]].w);
    147             }
    148             //printf("q[%d][%d].push(%d,%d)
    ",id[x][i],dir[x][i],x,d[x][i]);
    149             q[id[x][i]][dir[x][i]].push(A(x,d[x][i]));
    150         }
    151         //否则原为白色,应当出堆,但我们只需等待这个堆被询问时再更新即可(懒惰更新)
    152     }
    153 }
    154 int getans(int x){//更新点x对应的堆并返回当前答案
    155     //printf("getans(%d)
    ",x);
    156     while(!q[x][0].empty()&&col[q[x][0].top().x])q[x][0].pop();//更新左边的堆
    157     while(!q[x][1].empty()&&col[q[x][1].top().x])q[x][1].pop();//更新右边的堆
    158     if(q[x][0].empty()||q[x][1].empty())return 1<<31;//如果左右有一个为空则说明有一半没有白点
    159     else return q[x][0].top().d+q[x][1].top().d+e[eid[x]].w;
    160 }
    161 /*
    162 5
    163 1 2 1
    164 2 3 1
    165 2 4 -1
    166 4 5 3
    167 100000
    168 A
    169 C 5
    170 A
    171 C 3
    172 A
    173 C 5
    174 A
    175 C 5
    176 A
    177 C 5
    178 A
    179 C 5
    180 A
    181 C 2
    182 A
    183 C 1
    184 A
    185 C 4
    186 A
    187 C 2
    188 A
    189 C 4
    190 A
    191 C 3
    192 A
    193 C 2
    194 A
    195 */
    196 /*
    197 SPOJ2666 QTREE4
    198 基本思路就是边分治,每层中心边的两个端点存一个堆维护所代表子树中所有白点的距离,
    199 再存一个全局堆维护边分治树的每个点所产生的答案。
    200 翻转时在边分治树上修改logn个节点的堆即可,查询直接取全局堆的最大值,O(1)。
    201 细节问题:
    202 1.对每个点存它在深度为k的点分治树中到中心边的距离和属于中心边的哪一边,方便修改。
    203 2.开一个数组记录每个点当前颜色,取最大值时方便查询最大值是否合法,不合法则pop掉重新取。
    204 */
    View Code

    代码真的是错的……虽然把以1为根建树换成别的点就能过掉COGS上的数据,然而vjudge上怎么换都搞不过……

     

    寒假准备好好搞搞动态树分治……让我挖个大坑……

    bzoj4012 [HNOI2015]开店

    bzoj3435 [Wc2014]紫荆花之恋

  • 相关阅读:
    2019/5/13 洛谷P4742 【tarjan缩点 + 拓扑dp】
    图论500题
    欧拉回路与欧拉路径
    二分图的判定
    二分图的最大匹配以及带权匹配【匈牙利算法+KM算法】
    网络流三大算法【邻接矩阵+邻接表】POJ1273
    马拉车算法,mannacher查找最长回文子串
    tarjan算法(强连通分量 + 强连通分量缩点 + 桥(割边) + 割点 + LCA)
    luogu P5774 [JSOI2016]病毒感染 线性 dp
    luguo P2519 [HAOI2011]problem a dp+贪心
  • 原文地址:https://www.cnblogs.com/hzoier/p/6322469.html
Copyright © 2011-2022 走看看