输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。
接下来n-1行,每行2个整数u,v,为树上的一条无向边。
任何时刻,树上的任何权值大于等于0,且两两不同。
接下来1行,包括n个整数wi,表示初始时每个节点的权值。
接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。
接下来m行,每行包括三个整数 op,u,v:
op,u,v的含义见题目描述。
保证题目涉及的所有数在int内。
标签:get 节点 span 操作 bool sample stream dfs pen
我曾在弦歌之中听过你,
檀板声碎,半出折子戏。
舞榭歌台被风吹去,
岁月深处尚有余音一缕……
Gty神(xian)犇(chong)从来不缺妹子……
他来到了一棵妹子树下,发现每个妹子有一个美丽度……
由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣。
他想知道某个子树中美丽度大于k的妹子个数。
某个妹子的美丽度可能发生变化……
树上可能会出现一只新的妹子……
维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。
支持以下操作:
0 u x 询问以u为根的子树中,严格大于x的值的个数。(u^=lastans,x^=lastans)
1 u x 把u节点的权值改成x。(u^=lastans,x^=lastans)
2 u x 添加一个编号为"当前树中节点数+1"的节点,其父节点为u,其权值为x。(u^=lastans,x^=lastans)
最开始时lastans=0。
输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。
接下来n-1行,每行2个整数u,v,为树上的一条无向边。
任何时刻,树上的任何权值大于等于0,且两两不同。
接下来1行,包括n个整数wi,表示初始时每个节点的权值。
接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。
接下来m行,每行包括三个整数 op,u,v:
op,u,v的含义见题目描述。
保证题目涉及的所有数在int内。
对每个op=0,输出一行,包括一个整数,意义见题目描述。
题解:这题不是用带插入区间k小值维护DFS序就行吗?然而看discuss发现空间卡得要死,于是赶紧去学又好写又好理解的分块~
怎么做呢?插入时,如果父亲的块大小=B,那么就再开一块,否则就塞到父亲的块里。然后块内按权值排序;查询时,如果x的儿子y与x在同一块中,则暴力查询,否则直接在y的块里二分,然后递归做下去即可。
代码还是挺短的~
#include <cstdio> #include <cstring> #include <iostream> #include <vector> #include <algorithm> #include <cmath> #define lb(A,B) (lower_bound(s[A].begin(),s[A].end(),B,cmp)-s[A].begin()) using namespace std; const int maxn=60010; int n,m,tot,B,cnt,CNT,ans; int fa[maxn],to[maxn<<1],next[maxn<<1],head[maxn],bel[maxn],v[maxn],siz[maxn],TO[maxn<<1],NEXT[maxn<<1],HEAD[maxn]; vector<int> s[maxn]; inline void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } inline void ADD(int a,int b) { TO[CNT]=b,NEXT[CNT]=HEAD[a],HEAD[a]=CNT++; } void dfs(int x) { if(x==1||siz[bel[fa[x]]]==B) bel[x]=++tot,ADD(bel[fa[x]],bel[x]); else bel[x]=bel[fa[x]]; siz[bel[x]]++,s[bel[x]].push_back(x); for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]) fa[to[i]]=x,dfs(to[i]); } bool cmp(const int &a,const int &b) { return v[a]<v[b]; } void calc(int x,int y) { v[0]=y+1; int t=lb(x,0); ans+=siz[x]-t; for(int i=HEAD[x];i!=-1;i=NEXT[i]) calc(TO[i],y); } void query(int x,int y) { ans+=(v[x]>y); for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]) { if(bel[to[i]]==bel[x]) query(to[i],y); else calc(bel[to[i]],y); } } inline void insert(int x,int y) { if(siz[bel[x]]==B) bel[y]=++tot,ADD(bel[x],bel[y]); else bel[y]=bel[x]; add(x,y),fa[y]=x,x=bel[y],siz[x]++,s[x].push_back(y); for(int t=siz[x]-1;t&&v[s[x][t-1]]>v[y];t--) swap(s[x][t-1],s[x][t]); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { //freopen("bz3720.in","r",stdin); n=rd(),B=int(ceil(2*sqrt(double(n)))); int i,t,a,b,c,op; memset(head,-1,sizeof(head)),memset(HEAD,-1,sizeof(HEAD)); for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a); dfs(1); for(i=1;i<=n;i++) v[i]=rd(); for(i=1;i<=tot;i++) sort(s[i].begin(),s[i].end(),cmp); m=rd(); for(i=1;i<=m;i++) { op=rd(),a=rd()^ans,b=rd()^ans; if(op==0) ans=0,query(a,b),printf("%d\n",ans); if(op==1) { c=bel[a],t=lb(c,a),v[a]=b; for(;t<siz[c]-1&&v[s[c][t+1]]<b;t++) swap(s[c][t+1],s[c][t]); for(;t&&v[s[c][t-1]]>b;t--) swap(s[c][t-1],s[c][t]); } if(op==2) v[++n]=b,insert(a,n); } return 0; }
标签:get 节点 span 操作 bool sample stream dfs pen
原文地址:http://www.cnblogs.com/CQzhangyu/p/7514566.html