【块状树】bzoj3731 Gty的超级妹子树

带 加点 删边的块状树。

加点在 bzoj3720 说过。

删边其实就是块顶打标记,记录其属于哪棵树,防止在dfs搜集答案时跑到别的树上。

然后暴力把所在块拆开。

好像用邻接表存图,直接在vector里删边也行?

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<vector>
  5 using namespace std;
  6 #define maxn 200001
  7 int Res,Num;char C,CH[20];
  8 inline int Ge()
  9 {
 10     Res=0;C=‘*‘;
 11     while(C<‘0‘||C>‘9‘)C=getchar();
 12     while(C>=‘0‘&&C<=‘9‘){Res=Res*10+(C-‘0‘);C=getchar();}
 13     return Res;
 14 }
 15 inline void P(int x)
 16 {
 17     Num=0;if(!x){putchar(‘0‘);puts("");return;}
 18     while(x>0)CH[++Num]=x%10,x/=10;
 19     while(Num)putchar(CH[Num--]+48);
 20     putchar(‘\n‘);
 21 }
 22 typedef vector<int>::iterator ITER;
 23 vector<int>List[maxn],Goto[maxn];
 24 struct Graph
 25 {
 26     int v[maxn<<1],first[maxn<<1],next[maxn<<1],en;
 27     void AddEdge(const int &a,const int &b)
 28     {v[++en]=b;next[en]=first[a];first[a]=en;}
 29 };
 30 Graph G,son;
 31 int top[maxn],siz[maxn],sz,w[maxn],belong_tree[maxn];
 32 bool vis[maxn],root[maxn];
 33 int n,x,y,m,op,tree_num;
 34 int ans,val,U;
 35 void makeblock(int cur)
 36 {
 37     vis[cur]=true;
 38     for(int i=G.first[cur];i;i=G.next[i])
 39       if(!vis[G.v[i]])
 40         {
 41           son.AddEdge(cur,G.v[i]);
 42           if(siz[top[cur]]<sz)
 43             {
 44               List[top[cur]].push_back(w[G.v[i]]);
 45               siz[top[cur]]++;
 46               top[G.v[i]]=top[cur];
 47             }
 48           makeblock(G.v[i]);
 49         }
 50 }
 51 void makeGoto(int cur)
 52 {
 53     for(int i=son.first[cur];i;i=son.next[i])
 54       {
 55           if(top[son.v[i]]!=top[cur])
 56           Goto[top[cur]].push_back(son.v[i]);
 57         makeGoto(son.v[i]);
 58       }
 59 }
 60 void dfs(int cur)//在Goto树上询问
 61 {
 62     ans+=( List[cur].end() - upper_bound( List[cur].begin() , List[cur].end() , val ) );
 63     for(ITER it=Goto[cur].begin();it!=Goto[cur].end();it++)
 64       if(belong_tree[*it]==belong_tree[cur])//通过标记控制在一棵树内
 65         dfs(*it);
 66 }
 67 void dfs_block(int cur)//在块内询问
 68 {
 69     if(w[cur]>val) ans++;
 70     for(int i=son.first[cur];i;i=son.next[i])
 71       if(top[son.v[i]]==top[cur]) dfs_block(son.v[i]);
 72       else if(belong_tree[son.v[i]]==belong_tree[top[cur]]) dfs(son.v[i]);
 73 }
 74 void query()
 75 {
 76     ans=0;
 77     if(U==top[U]) dfs(U);
 78     else dfs_block(U);
 79     P(ans);
 80 }
 81 void update()
 82 {
 83     List[top[U]].erase( lower_bound(List[top[U]].begin(),List[top[U]].end(),w[U]) );
 84     w[U]=val;
 85     List[top[U]].insert( lower_bound(List[top[U]].begin(),List[top[U]].end(),val+1) , val );
 86 }
 87 void AddPoint()
 88 {
 89     n++;
 90     if(siz[top[U]]<sz)
 91       {
 92           top[n]=top[U];
 93           siz[top[n]]++;
 94       }
 95     else
 96       {
 97           top[n]=n;
 98           siz[n]++;
 99           Goto[top[U]].push_back(n);
100           belong_tree[n]=belong_tree[top[U]];
101       }
102     son.AddEdge(U,n);
103     w[n]=val;
104     List[top[n]].insert( lower_bound(List[top[n]].begin(),List[top[n]].end(),val+1) , val );
105 }
106 void dfs_split(int cur)//设置每个块顶属于哪个树的标记
107 {
108     for(ITER it=Goto[cur].begin();it!=Goto[cur].end();it++)
109       if(belong_tree[cur]==belong_tree[*it])
110         dfs_split(*it);
111     belong_tree[cur]=tree_num;
112 }
113 void dfs_split_block(int cur)//把分裂的块的下半部分重构块
114 {
115     List[U].push_back(w[cur]);
116     for(int i=son.first[cur];i;i=son.next[i])
117       {
118           if(top[son.v[i]]==top[cur])
119           dfs_split_block(son.v[i]);
120         else if(belong_tree[son.v[i]]==belong_tree[top[U]])//顺手设置它下面的块的标记
121           {
122             Goto[U].push_back(son.v[i]);
123             dfs_split(son.v[i]);
124           }
125         siz[U]++;
126       }
127     top[cur]=U;
128 }
129 void dfs_remain_block(int cur)//把分裂的块的上半部分重构块
130 {
131     List[top[U]].push_back(w[cur]); siz[top[U]]++;
132     for(int i=son.first[cur];i;i=son.next[i])
133       if( (!root[son.v[i]]) && (top[son.v[i]]==top[cur]) )
134         dfs_remain_block(son.v[i]);
135 }
136 void Delete_Edge()
137 {
138     root[U]=true;
139     tree_num++;
140     if(U!=top[U])
141       {
142           List[top[U]].clear();siz[top[U]]=0;
143           dfs_remain_block(top[U]);
144           sort(List[top[U]].begin(),List[top[U]].end());//重构分裂的块的上半部分
145           dfs_split_block(U);
146           belong_tree[U]=tree_num;
147           sort(List[U].begin(),List[U].end());//重构分裂的块的下半部分
148       }
149     else
150       dfs_split(U);
151 }
152 int main()
153 {
154     n=Ge();
155     for(int i=1;i<n;i++)
156       {
157           x=Ge();y=Ge();
158           G.AddEdge(x,y);
159           G.AddEdge(y,x);
160       }
161     sz=sqrt((double)n*log2(n));
162     for(int i=1;i<=n;i++)
163       {
164           w[i]=Ge();
165           top[i]=i;
166           siz[i]=1;
167       }
168     makeblock(1);
169     for(int i=1;i<=n;i++)
170       if(top[i]==i)
171         {
172           List[i].push_back(w[i]);
173           sort(List[i].begin(),List[i].end());
174         }
175     makeGoto(1);
176     root[1]=true;
177     m=Ge();
178     for(int i=1;i<=m;i++)
179       {
180           op=Ge();U=Ge();U^=ans;
181           if(!op){val=Ge();val^=ans;query();}
182           else if(op==1){val=Ge();val^=ans;update();}
183           else if(op==2){val=Ge();val^=ans;AddPoint();}
184           else Delete_Edge();
185       }
186     return 0;
187 }
时间: 2024-10-04 09:23:18

【块状树】bzoj3731 Gty的超级妹子树的相关文章

bzoj3731: Gty的超级妹子树

一代神题啊orz(至少是以前年代的神题吧) 块状树 复杂度nsqrtnlogn 真是exciting 还没有卡时限 话不多说直接上代码 (最近解锁了记事本写代码的技能...感觉越来越依赖OJ调试了...啊感觉写代码准确率高了不少qwq) #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <

BZOJ 3720: Gty的妹子树

3720: Gty的妹子树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1493  Solved: 502[Submit][Status][Discuss] Description 我曾在弦歌之中听过你, 檀板声碎,半出折子戏. 舞榭歌台被风吹去, 岁月深处尚有余音一缕…… Gty神(xian)犇(chong)从来不缺妹子…… 他来到了一棵妹子树下,发现每个妹子有一个美丽度…… 由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣. 他想知道

3720: Gty的妹子树

3720: Gty的妹子树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1440  Solved: 482[Submit][Status][Discuss] Description 我曾在弦歌之中听过你, 檀板声碎,半出折子戏. 舞榭歌台被风吹去, 岁月深处尚有余音一缕…… Gty神(xian)犇(chong)从来不缺妹子…… 他来到了一棵妹子树下,发现每个妹子有一个美丽度…… 由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣. 他想知道

【BZOJ3720】Gty的妹子树 块状树

[BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现每个妹子有一个美丽度……由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣.他想知道某个子树中美丽度大于k的妹子个数.某个妹子的美丽度可能发生变化……树上可能会出现一只新的妹子……维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi.支持以下操作:0 u x 

【块状树】【博弈论】bzoj3729 Gty的游戏

块状树,每个块的根记录一下当前块内距块根为奇数距离的异或和和偶数距离的异或和,询问的时候讨论一下即可. 总的节点数可能超过50000. #include<cstdio> #include<cmath> using namespace std; #define N 100001 int n,m,L,a[N]; int en,v[N<<1],next[N<<1],first[N]; int e2,v2[N<<1],nex2[N<<1],f

BZOJ 1086 SCOI2005 王室联邦 块状树

题目大意:给定一棵树,要求将这棵树分成一些块,使每块大小在[B,3B]之间 <手把手教你块状树系列> - -终于搞懂这题怎么做了 - -去网上扒了个代码居然是错的 坑死我了 - -还好题解的思想是对的 朴素的分块方式是贪心 能加就加 这种方法存在着严重的效率问题 可以被菊花卡成O(n)块 因此我们可以为其它的块预留位置 如果一块大小刚好>=b 就将这坨东西分成一块 首先任选一点开始深搜 维护一个栈 每个点退出递归时压栈 自下至上进行合并 如果某棵子树深搜完之后栈内元素数>=b 就把

【块状树】【树链剖分】bzoj1036 [ZJOI2008]树的统计Count

很早之前用树链剖分写过,但是代码太长太难写,省选现场就写错了. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 #define lson rt<<1,l,m 6 #define rson rt<<1|1,m+1,r 7 #define maxn 60000 8 int n,m,u,v; 9 int V[maxn],Next[

【kruscal】【最小生成树】【块状树】bzoj3732 Network

跟去年NOIP某题基本一样. 最小生成树之后,就变成了询问连接两点的路径上的权值最大的边. 倍增LCA.链剖什么的随便搞. 块状树其实也是很简单的,只不过每个点的点权要记录成“连接其与其父节点的边的权值”,然后暴力LCA时不要用LCA的值更新答案了. 1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #

【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行

离线后以宗教为第一关键字,操作时间为第二关键字排序. <法一>块状树,线下ac,线上tle…… #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; queue<int>q; int f,c; inline void R(int &x){ c=0;f=1;