BZOJ2631: tree
题解: LCT 类似维护一次函数 a*x+b 的双标记
/**************************************************************
Problem: 2631
User: c20161007
Language: C++
Result: Accepted
Time:21336 ms
Memory:9352 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <vector>
#define ll unsigned int
const int MAXN=1e5+10;
const int lth=51061;
using namespace std;
//ll readll(){
// ll x=0,f=1;char ch=getchar();
// while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
// while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
// return x*f;
//}
int readint(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int ch[MAXN][2],pre[MAXN],rt[MAXN],size[MAXN],n,q;
ll key[MAXN],sum[MAXN],add[MAXN],res[MAXN],mul[MAXN];
void Treavel(int x)
{
if(x)
{
// cout<<x<<endl;
Treavel(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]);
Treavel(ch[x][1]);
}
}
void debug(int rp)
{
printf("root:%d\n",rp);
Treavel(rp);
}
void update(int r,ll vul1,ll vul2){
if(!r) return ;
sum[r]=((sum[r]*vul1)%lth+(size[r]*vul2)%lth)%lth;
key[r]=((vul1*key[r])%lth+vul2)%lth;
mul[r]=(mul[r]*vul1)%lth;
add[r]=((add[r]*vul1)%lth+vul2)%lth;
}
void update_add(int r,ll vul){
if(!r) return ;
key[r]=(vul+key[r])%lth;
sum[r]=(sum[r]+1ll*size[r]*vul)%lth;
add[r]=(add[r]+vul)%lth;
}
void update_mul(int r,ll vul){
if(!r) return ;
key[r]=(key[r]*vul)%lth;
sum[r]=(sum[r]*vul)%lth;
mul[r]=(mul[r]*vul)%lth;
add[r]=(add[r]*vul)%lth;
}
void update_res(int r){
if(!r) return ;
swap(ch[r][0],ch[r][1]);
res[r]^=1;
}
void push(int x){
if(res[x]){
update_res(ch[x][0]);
update_res(ch[x][1]);
res[x]^=1;
}
update(ch[x][0],mul[x],add[x]);
update(ch[x][1],mul[x],add[x]);
mul[x]=1,add[x]=0;
}
void up(int x){
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+key[x])%lth;
}
void P(int r){
if(!rt[r]) P(pre[r]);
push(r);
}
void rotate(int x,int kind){
int y=pre[x];
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(rt[y]) rt[y]=0,rt[x]=1;
else ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
up(y);
}
void splay(int x){
P(x);
//cout<<x<<"-----"<<rt[x]<<endl;
while(!rt[x]){
if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
else{
int y=pre[x];int kind=ch[pre[y]][0]==y;
if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
else rotate(y,kind),rotate(x,kind);
}
}
up(x);
}
void access(int x){
int y=0;
//cout<<x<<endl;
//cout<<pre[1]<<"-----"<<endl;
// cout<<x<<" "<<pre[x]<<endl;
while(x){
splay(x);
//debug(x);
//cout<<x<<"------"<<y<<endl;
if(ch[x][1]) rt[ch[x][1]]=1,pre[ch[x][1]]=x,ch[x][1]=0;
ch[x][1]=y;
up(x);
if(y) rt[y]=0,pre[y]=x;
y=x;x=pre[x];
// cout<<x<<" "<<y<<endl;
}
//debug(1);
return ;
}
void mroot(int x){
access(x);//debug(x);
splay(x);//debug(x);
//cout<<pre[1]<<"====="<<endl;
//debug(x);
update_res(x);
//up(x);
return ;
}
void operator_add(int u,int v,ll vul){
mroot(u);access(v);splay(u);
update_add(u,vul);
return ;
}
void operator_chong(int u1,int v1,int u2,int v2){
mroot(u1);access(v1);splay(v1);
ch[v1][0]=0;up(v1);
pre[u1]=pre[v1]=0;rt[u1]=rt[v1]=1;
mroot(u2);pre[u2]=v2;
}
void operator_mul(int u,int v,ll vul){
//cout<<u<<" "<<v<<endl;
// cout<<u<<" "<<v<<" "<<pre[u]<<" "<<pre[v]<<endl;
// debug(u);debug(v);
mroot(u);
//debug(u);
// cout<<rt[v]<<endl;
access(v);//debug(v);
splay(u);
update_mul(u,vul);
}
int operator_querty(int u,int v){
//cout<<pre[u]<<" "<<pre[v]<<endl;
//if(u==v) return key[u]%lth;
mroot(u);//debug(u);
//cout<<pre[1]<<"------"<<endl;
access(v);//debug(v);
splay(u);
// debug(u);
return sum[u]%lth;
}
vector<int>vec[MAXN];
void dfs(int v,int fa){
pre[v]=fa;
for(int i=0;i<vec[v].size();i++){
if(vec[v][i]!=fa) dfs(vec[v][i],v);
}
}
int main(){
ios::sync_with_stdio(false);
n=readint();q=readint();
for(int i=1;i<=n;i++){
ch[i][0]=ch[i][1]=pre[i]=add[i]=res[i]=0;
size[i]=rt[i]=key[i]=sum[i]=mul[i]=1;
}
char ch;int u,v,u1,v1;ll x;
for(int i=1;i<n;i++){
u=readint();v=readint();
vec[u].push_back(v);vec[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=q;i++){
scanf(" %c",&ch);u=readint();v=readint();
if(ch=='+'){
scanf("%d\n",&x);operator_add(u,v,x%lth);
}
else if(ch=='-'){
scanf("%d\n",&u1);scanf("%d\n",&v1);
operator_chong(u,v,u1,v1);
}
else if(ch=='*'){
scanf("%d\n",&x);
operator_mul(u,v,x%lth);
}
else printf("%d\n",operator_querty(u,v));
}
return 0;
}
2631: tree
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 5381 Solved: 1811
[Submit][Status][Discuss]
Description
一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c:将u到v的路径上的点的权值都加上自然数c;
- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
* u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
Input
第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
对于每个/对应的答案输出一行
Sample Input
3 2
1 2
2 3
* 1 3 4
/ 1 1
1 2
2 3
* 1 3 4
/ 1 1
Sample Output
4
HINT
数据规模和约定
10%的数据保证,1<=n,q<=2000
另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链
另外35%的数据保证,1<=n,q<=5*10^4,没有-操作
100%的数据保证,1<=n,q<=10^5,0<=c<=10^4

浙公网安备 33010602011771号