bzoj2631 tree(路径权值的加乘操作)
来源:互联网 发布:电视网络播放量排行榜 编辑:程序博客网 时间:2024/06/07 02:43
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
分析:
LCT的经典操作+扩展操作
题目中比较难处理的就是路径权值的更改
我们起一次接触同时乘除的操作,是在线段树
实际上这道题就可以运用这个思想:
用两个数组分别记录加(ad)乘(mul)标记,
每次在更新一条路径的时候,我们就像询问时一样,把整条路径的信息都转换到一个点上
这样操作就简化成了点操作:
sum=sum*mul+size*ad
v=v*mul+ad
难度在于标记下传:
首先我们要维护儿子结点的加乘标记
mul[ch]=mul[ch]*mul[fa]
ad[ch]=ad[ch]*mul[fa]+ad[fa]
对于值的修改可以浓缩成这个函数:
void cal(int x,ll a,ll b) //a乘标记,b加标记{ if (!x) return; v[x]=(v[x]*a+b)%mod; sum[x]=(sum[x]*a+size[x]*b)%mod; ad[x]=(ad[x]+b)%mod; mul[x]=(mul[x]*a)%mod;}
tip
每个点的初始权值为1
在维护sum的同时,不要忘了维护v
数据要求开unsigned int
我偷了个懒,直接开ll,但是一开始一直是T,我觉得应该是和ll有关,改成了unsigned int就A了
不要忘了取%
为了降低代码复杂度
在push,add和multi的时候都可以调用cal函数
//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#define ll unsigned intusing namespace std;const ll mod=51061;const int N=100010;int ch[N][2],pre[N],q[N],n,Q;ll v[N],sum[N],ad[N],mul[N],size[N];bool rev[N];int get(int bh){ return (ch[pre[bh]][0]==bh? 0:1);}int isroot(int bh){ return ch[pre[bh]][0]!=bh&&ch[pre[bh]][1]!=bh;}void update(int bh){ if (!bh) return; sum[bh]=v[bh]; if (ch[bh][0]) sum[bh]+=sum[ch[bh][0]]; if (ch[bh][1]) sum[bh]+=sum[ch[bh][1]]; sum[bh]%=mod; size[bh]=1; if (ch[bh][0]) size[bh]+=size[ch[bh][0]]; if (ch[bh][1]) size[bh]+=size[ch[bh][1]]; size[bh]%=mod;}void cal(int x,ll a,ll b) //a乘标记,b加标记{ if (!x) return; v[x]=(v[x]*a+b)%mod; sum[x]=(sum[x]*a+size[x]*b)%mod; ad[x]=(ad[x]*a+b)%mod; mul[x]=(mul[x]*a)%mod;}void push(int bh){ if (!bh) return; if (rev[bh]) { if (ch[bh][0]) rev[ch[bh][0]]^=1; if (ch[bh][1]) rev[ch[bh][1]]^=1; rev[bh]^=1; swap(ch[bh][0],ch[bh][1]); } if (ad[bh]!=0||mul[bh]!=1) { cal(ch[bh][0],mul[bh],ad[bh]); cal(ch[bh][1],mul[bh],ad[bh]); } mul[bh]=1; ad[bh]=0;}void rotate(int bh){ int fa=pre[bh]; int grand=pre[fa]; int wh=get(bh); if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=bh; pre[bh]=grand; ch[fa][wh]=ch[bh][wh^1]; pre[ch[fa][wh]]=fa; ch[bh][wh^1]=fa; pre[fa]=bh; update(fa); update(bh);}void splay(int bh){ int top=0; q[++top]=bh; for (int i=bh;!isroot(i);i=pre[i]) q[++top]=pre[i]; while (top) push(q[top--]); for (int fa;!isroot(bh);rotate(bh)) if (!isroot(fa=pre[bh])) rotate(get(fa)==get(bh)? fa:bh);}void expose(int bh){ int t=0; while (bh) { splay(bh); ch[bh][1]=t; update(bh); // t=bh; bh=pre[bh]; }}void makeroot(int bh){ expose(bh); splay(bh); rev[bh]^=1;}void link(int x,int y){ makeroot(x); pre[x]=y;}void cut(int x,int y){ makeroot(x); expose(y); splay(y); pre[x]=ch[y][0]=0;}int find(int x){ expose(x); splay(x); while (ch[x][0]) x=ch[x][0]; return x;}int askdis(int x,int y){ makeroot(x); expose(y); splay(y); return size[ch[y][0]];}ll asksum(int x,int y){ makeroot(x); expose(y); splay(y); return sum[y]%mod;}void changepo(int x,ll z){ makeroot(x); v[x]=z; update(x);}void add(int x,int y,ll z){ makeroot(x); expose(y); splay(y); cal(y,1,z);}void multi(int x,int y,ll z){ makeroot(x); expose(y); splay(y); cal(y,z,0);}int main(){ scanf("%d%d",&n,&Q); for (int i=1;i<=n;i++) { ad[i]=0; mul[i]=size[i]=v[i]=sum[i]=1; rev[i]=0; } for (int i=1;i<n;i++) { int u,w; scanf("%d%d",&u,&w); link(u,w); } char s[10]; int u1,w1,u2,w2; for (int i=1;i<=Q;i++) { scanf("%s",s); if (s[0]=='+') { scanf("%d%d%d",&u1,&w1,&u2); add(u1,w1,(ll)u2); //改变路径权值 } else if (s[0]=='-') { scanf("%d%d%d%d",&u1,&w1,&u2,&w2); cut(u1,w1); link(u2,w2); } else if (s[0]=='*') { scanf("%d%d%d",&u1,&w1,&u2); multi(u1,w1,(ll)u2); } else { scanf("%d%d",&u1,&w1); printf("%d\n",asksum(u1,w1)); } } return 0;}
阅读全文
0 0
- bzoj2631 tree(路径权值的加乘操作)
- [BZOJ2631]tree(LCT)
- BZOJ2631:tree(LCT)
- [BZOJ2631]tree(LCT)
- bzoj2631 tree
- bzoj2631: tree
- 【BZOJ2631】tree
- bzoj2631 tree
- [BZOJ2631] tree
- [BZOJ2631]tree
- BZOJ2631: tree
- bzoj2631: tree
- Bzoj2631 Tree
- bzoj2631 tree
- BZOJ2631: tree
- 【bzoj2631】tree
- bzoj2631 tree
- 【bzoj2631】tree
- make -C $(KDIR) M=$(PWD) modules
- C++函数指针
- 【多线程】(三)java.lang.Thread小结
- redis之proxy集群之twemproxy
- 随便写写先
- bzoj2631 tree(路径权值的加乘操作)
- 内存四区模型与指针
- 11月25日学习笔记__filter 和 sorted
- 链接
- 动态规划之最长公共子序列
- Spark 提交任务时 Invalid signature file digest 错误
- IIS 部署 FTP 文件共享
- myBatis 中查询多表数据时使用association处理一对一关联
- Docker 登录远程仓库Harbor https 问题