标签:bool input content struct 标记 int 过程 play 问题
8 6
1 2
1 3
2 8
3 4
3 5
3 6
4 7
REQUEST 7
RELEASE 3
REQUEST 3
RECENTER 5
RELEASE 2
REQUEST 1
4.0000000000
2.0000000000
1.3333333333
N<=100000 ,M<=100000
调了几个世纪终于调出来了……LCT+dfs序线段树。
令每个点权值为这个点到根的路径上虚边数+1,一开始时都是虚边,点权即为深度。
操作1可以神转换为access。在access过程中,当前节点的右儿子所代表的子树整体权值+1(因为虚边+1),而即将拼接过来的子树整体权值-1。
操作2因为有换根操作,所以需要分类讨论一波(以下结论画图易得):
1. x=root,查询整棵树;
2. root不在x的子树内,查询原树中x的子树;
3. root在x的子树内,查询整棵树去除掉包含root的以x的亲儿子为根的子树。
然后就可以开始瞎搞啦?
(顺便吐槽一句,结构体好丑啊T_T本来以为写结构体会快一些的,其实……仿佛差不多
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100010; 6 int n,m,x,y,cnt,dfsn,rt=1;//注意初始化rt为1 7 int head[N],st[N]; 8 struct edge{int u,v,next;}e[N*2];//邻接表 9 struct leaf{int l,r;long long sum,tag;}t[N*4];//线段树 10 struct node{int p,fa,c[2],deep,in,out;bool rev;}tr[N];//splay 11 int read() 12 { 13 int x=0,f=1;char c=getchar(); 14 while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} 15 while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} 16 return x*f; 17 } 18 void ins(int a,int b){cnt++;e[cnt].u=a;e[cnt].v=b;e[cnt].next=head[a];head[a]=cnt;} 19 void insert(int a,int b){ins(a,b);ins(b,a);} 20 void qadd(int num,long long w) 21 { 22 t[num].tag+=w; 23 t[num].sum+=(long long)(t[num].r-t[num].l+1)*w; 24 } 25 void pushup(int num){t[num].sum=t[num<<1].sum+t[num<<1|1].sum;} 26 void pushdown(int num)//线段树下传tag 27 { 28 if(!t[num].tag)return; 29 qadd(num<<1,t[num].tag); 30 qadd(num<<1|1,t[num].tag); 31 t[num].tag=0; 32 } 33 bool isroot(int k){return !k||(tr[tr[k].fa].c[0]!=k&&tr[tr[k].fa].c[1]!=k);} 34 void down(int k)//下传翻转标记 ,注意不要跟pushdown弄混 35 { 36 if(tr[k].rev) 37 { 38 int l=tr[k].c[0],r=tr[k].c[1]; 39 tr[k].rev^=1;tr[l].rev^=1;tr[r].rev^=1; 40 swap(tr[k].c[0],tr[k].c[1]); 41 } 42 } 43 void rotate(int x) 44 { 45 int y=tr[x].fa,z=tr[y].fa,l,r; 46 if(tr[y].c[0]==x)l=0;else l=1;r=l^1; 47 if(!isroot(y)){if(tr[z].c[0]==y)tr[z].c[0]=x;else tr[z].c[1]=x;} 48 tr[x].fa=z;tr[y].fa=x;tr[tr[x].c[r]].fa=y; 49 tr[y].c[l]=tr[x].c[r];tr[x].c[r]=y; 50 } 51 void splay(int x) 52 { 53 int top=0;st[++top]=x; 54 for(int i=x;!isroot(i);i=tr[i].fa)st[++top]=tr[i].fa; 55 for(int i=top;i;i--)down(st[i]); 56 while(!isroot(x)) 57 { 58 int y=tr[x].fa,z=tr[y].fa; 59 if(!isroot(y)) 60 { 61 if((tr[y].c[0]==x)^(tr[z].c[0]==y))rotate(x); 62 else rotate(y); 63 } 64 rotate(x); 65 } 66 } 67 void build(int num,int l,int r) 68 { 69 t[num].l=l;t[num].r=r; 70 if(l==r)return; 71 int mid=(l+r)>>1; 72 build(num<<1,l,mid);build(num<<1|1,mid+1,r); 73 } 74 void add(int num,int l,int r,long long w)//线段树区间加 75 { 76 if(l>r)return; 77 if(l<=t[num].l&&t[num].r<=r){qadd(num,w);return;} 78 if(t[num].l==t[num].r)return; 79 pushdown(num); 80 int mid=(t[num].l+t[num].r)>>1; 81 if(l<=mid)add(num<<1,l,r,w); 82 if(r>mid)add(num<<1|1,l,r,w); 83 pushup(num); 84 } 85 void dfs(int now,int last) 86 { 87 tr[now].p=tr[now].fa=last; 88 tr[now].in=++dfsn; 89 tr[now].deep=tr[last].deep+1; 90 add(1,tr[now].in,tr[now].in,tr[now].deep);//在线段树中更新 91 for(int i=head[now];i;i=e[i].next) 92 if(e[i].v!=last)dfs(e[i].v,now);//记得判父节点 93 tr[now].out=dfsn; 94 } 95 long long query(int num,int l,int r)//线段树区间求和 96 { 97 if(l>r)return 0; 98 if(l<=t[num].l&&t[num].r<=r)return t[num].sum; 99 pushdown(num);//记得下传tag 100 long long ans=0; 101 int mid=(t[num].l+t[num].r)>>1; 102 if(l<=mid)ans+=query(num<<1,l,r); 103 if(r>mid)ans+=query(num<<1|1,l,r); 104 return ans; 105 } 106 int find(int num,int goal)//查找goal在num的哪一棵子树内 107 { 108 for(int i=head[num];i;i=e[i].next) 109 if(e[i].v!=tr[num].p&&tr[goal].in>=tr[e[i].v].in&&tr[goal].out<=tr[e[i].v].out)return e[i].v; 110 return 0; 111 } 112 double ask(int num)//REQUEST 113 { 114 if(num==rt)return (double)query(1,1,n)/n; 115 if(tr[rt].in>=tr[num].in&&tr[rt].out<=tr[num].out)//如果rt在num的子树内;这里的子树是相对于原树而言 116 { 117 int r=find(num,rt); 118 return (double)(query(1,1,tr[r].in-1)+query(1,tr[r].out+1,n))/(n-(tr[r].out-tr[r].in+1)); 119 } 120 return (double)query(1,tr[num].in,tr[num].out)/(tr[num].out-tr[num].in+1); 121 } 122 int top(int num) 123 { 124 down(num); 125 while(tr[num].c[0])num=tr[num].c[0],down(num); 126 return num; 127 } 128 void ladd(int num,int w)//子树整体权值加减 129 { 130 if(num==rt)add(1,1,n,w); 131 else if(tr[rt].in>=tr[num].in&&tr[rt].out<=tr[num].out) 132 { 133 int r=find(num,rt); 134 add(1,1,tr[r].in-1,w); 135 add(1,tr[r].out+1,n,w); 136 } 137 else add(1,tr[num].in,tr[num].out,w); 138 } 139 void acs(int num) 140 { 141 int r=0; 142 while(num) 143 { 144 splay(num); 145 if(tr[num].c[1])ladd(top(tr[num].c[1]),1); 146 if(r)ladd(top(r),-1); 147 tr[num].c[1]=r;r=num;num=tr[num].fa; 148 } 149 } 150 void mrt(int num){splay(num);rt=num;tr[num].rev^=1;}//据题意,换根前已经access过了 151 int main() 152 { 153 char ch[15]; 154 n=read();m=read(); 155 for(int i=1;i<n;i++)x=read(),y=read(),insert(x,y); 156 build(1,1,n);dfs(1,0); 157 while(m--) 158 { 159 scanf("%s",ch);x=read(); 160 if(ch[2]==‘Q‘)printf("%.10lf\n",ask(x)); 161 else 162 { 163 acs(x); 164 if(ch[2]==‘C‘)mrt(x); 165 } 166 } 167 return 0; 168 }
标签:bool input content struct 标记 int 过程 play 问题
原文地址:http://www.cnblogs.com/zsnuo/p/7076159.html