bzoj 2631 LCT


/**************************************************************
Problem: 2631
User: wangyucheng
Language: C++
Result: Accepted
Time:18408 ms
Memory:9252 kb
****************************************************************/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 110000
#define uint unsigned int
int rt[N];
int ch[N][2];
int pre[N];
uint s[N],c[N];
uint sum[N];
uint siz[N];
int rev[N];
uint val[N];
const uint mod=51061;
int n,q;
int nn,e[N],ne[N*2],v[N*2];
void add(int x,int y){
ne[++nn]=e[x],e[x]=nn,v[nn]=y;
}
void mul(int x,uint y){
if(!x)return;
sum[x]=(sum[x]*y)%mod;
val[x]=(val[x]*y)%mod;
s[x]=(s[x]*y)%mod;
c[x]=(c[x]*y)%mod;
}
void revs(int x){
if(!x)return;
rev[x]^=1;
swap(ch[x][0],ch[x][1]);
}
void plu(int x,uint y){
if(!x)return;
val[x]=(val[x]+y)%mod;
sum[x]=(siz[x]%mod*y+sum[x])%mod;
s[x]=(s[x]+y)%mod;
}
void push(int x){
if(rev[x]){
revs(ch[x][0]);
revs(ch[x][1]);
rev[x]=0;
}
if(c[x]!=1){
mul(ch[x][0],c[x]);
mul(ch[x][1],c[x]);
c[x]=1;
}
if(s[x]){
plu(ch[x][0],s[x]);
plu(ch[x][1],s[x]);
s[x]=0;
}
}
void up(int x){
sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+val[x])%mod;
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void rotate(int x){
int y=pre[x],z=pre[y],k=ch[y][0]==x;
pre[ch[y][!k]=ch[x][k]]=y;
pre[ch[x][k]=y]=x;
pre[x]=z;
if(!rt[y])ch[z][ch[z][1]==y]=x;
else rt[y]=0,rt[x]=1;
up(y);
}
void dfs(int x){
if(!rt[x])dfs(pre[x]);
push(x);
}
void splay(int x){
dfs(x);
int y,z;
for(;!rt[x];){
y=pre[x],z=pre[y];
if(rt[y])rotate(x);
else if((ch[y][1]==x)^(ch[z][1]==y))rotate(x),rotate(x);
else rotate(y),rotate(x);
}
up(x);
}
int acess(int x){
int y=0;
for(;x;y=x,x=pre[x]){
splay(x);
rt[ch[x][1]]=1;
ch[x][1]=y;
rt[y]=0;
up(x);
}
return y;
}
void cut(int x,int y){
acess(y);
splay(x);
if(pre[x]==y)pre[x]=0;
else{
acess(x);
splay(y);
pre[y]=0;
}
}
void makeroot(int x){
acess(x);
splay(x);
revs(x);
}
void link(int x,int y){
makeroot(x);
pre[x]=y;
}
int qu[N],he,bo;
void init(){
for(int i=1;i<=n;i++){
c[i]=1,siz[i]=1;
val[i]=1;
sum[i]=1;
rt[i]=1;
}
int x;
qu[he=bo=1]=1;
while(he>=bo){
for(int i=e[x=qu[bo++]];i;i=ne[i]){
if(!pre[v[i]]&&v[i]!=1)pre[v[i]]=x,qu[++he]=v[i];
}
}
}
int ask(int a,int b){
acess(a);
int y=acess(b);
if(y==a)return (sum[ch[a][1]]+val[a])%mod;
splay(a);
return (sum[ch[y][1]]+val[y]+sum[a])%mod;
}
void jia(int a,int b,uint z){
acess(a);
z%=mod;
int y=acess(b);
if(y==a){
plu(ch[y][1],z);
val[y]=(val[y]+z)%mod;
up(y);
return;
}
splay(a);
plu(a,z);
plu(ch[y][1],z);
val[y]=(val[y]+z)%mod;
up(y);
}
void cheng(int a,int b,uint z){
acess(a);
int y=acess(b);
z%=mod;
if(y==a){
mul(ch[y][1],z);
val[y]=(val[y]*z)%mod;
up(y);
return;
}
splay(a);
mul(a,z);
mul(ch[y][1],z);
val[y]=(val[y]*z)%mod;
up(y);
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
init();
for(int i=1;i<=q;i++){
char in;
int a,b,g,h;
scanf(" %c",&in);
if(in==‘+‘){
scanf("%d%d%d",&a,&b,&g);
jia(a,b,g);
}
if(in==‘/‘){
scanf("%d%d",&a,&b);
printf("%d\n",ask(a,b));
}
if(in==‘*‘){
scanf("%d%d%d",&a,&b,&g);
cheng(a,b,g);
}
if(in==‘-‘){
scanf("%d%d%d%d",&a,&b,&g,&h);
cut(a,b);
link(g,h);
}
}

}

bzoj 2631 LCT

时间: 2025-01-11 07:31:20

bzoj 2631 LCT的相关文章

BZOJ 2631: tree( LCT )

LCT...略麻烦... -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define

bzoj 2631

lct 基础(' '   ) 就当个纪念吧(' '    )  毕竟写了4h, cut 部分一直naive 总是想找谁是儿子,然后最后发现直接提根就好了啊(' '   ) #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll mod = 51061; co

bzoj 2631: tree 动态树+常数优化

2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1716  Solved: 576[Submit][Status] Description 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一:+ u v c:将u到v的路径上的点的权值都加上自然数c:- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树:* u v c:将u到v的

bzoj 3669 lct维护最小生成树

大概题意:给一个无向图,有a,b两种边权,找一条从1到n的路径,使得max(a[i])+max(b[i])最小a[i],b[i]表示该路径上的边的对应权. 如果用类似最短路的DP来做,显然每个点的状态就必须是一个集合,保存的是一个下凸的点集,表示到达这个点的最小的a,b,这样肯定会挂,但该该种做法已经无法再优化或减少状态了. 考虑枚举其中一个权值b0,然后只考虑所有b权值小于等于b0的边,然后变成简单的问题,因为这个b0不满足二分三分之类的性质,所以肯定不能每次重建图,跑DP,最终的做法是从小到

BZOJ 4668 LCT

思路: 这不是LCT裸题嘛23333 (好像并查集+按秩合并就可以搞了 我还是too young) 维护边权的话 就新加一个点 代表边 这个点想线段的两个端点连边就好了 //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=1000050; int n,m,op,xx,yy,top,lastans,T; int fa[N],ch[N][2],q[N],maxx[N],rev[N],v[N],f[N];

BZOJ 2002 LCT板子题

思路: LCT啊... (分块也行) 不过YOUSIKI出了一道"弹飞大爷" 就不能用分块水过去了 //By SiriusRen #include <cstdio> #include <algorithm> using namespace std; const int N=200050; int fa[N],ch[N][2],rev[N],size[N],n,op,q[N],top,a[N],m,xx,yy; bool isroot(int x){return

BZOJ 2843 LCT

这还是道LCT的题,跟着czl做了好多LCT的题啊!没事,czl带我飞!加油,不错,挺顺利的.加油!1592毫秒, 第一次考虑了代码量, 我写这个花了 2800的代码长度, 然而czl只有1900, 代码简化还是很重要啊! 1 #include<cstdio> 2 #include<iostream> 3 #define lc c[k][0] 4 #define rc c[k][1] 5 #define rep(i,j,k) for(int i = j; i <= k; i+

BZOJ 2631 tree 动态树(Link-Cut-Tree)

题目大意:维护一种树形数据结构.支持下面操作: 1.树上两点之间的点权值+k. 2.删除一条边.添加一条边,保证加边之后还是一棵树. 3.树上两点之间点权值*k. 4.询问树上两点时间点的权值和. 思路:利用动态树维护这棵树,lct的裸题.假设不会下传标记的,先去做BZOJ1798,也是这种标记,仅仅只是在线段树上做,比这个要简单很多. 这个也是我的LCT的第一题,理解起来十分困难啊... CODE: #include <cstdio> #include <cstring> #in

BZOJ 3514 LCT+主席树

思路: //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=400500; int n,m,k,type,ch[N][2],fa[N],minn[N],rev[N],q[N],top,pre[N]; int root[N],tree[N*50],lson[N*50],rson[N*50],cnt,xx,yy,ans; struct Road{int x,y,wei;}road[N]; bool isr