HDU 5405 Sometimes Naive 2015多校联合训练赛#9 LCT 树链剖分
来源:互联网 发布:键盘美化软件下载 编辑:程序博客网 时间:2024/05/01 16:50
Sometimes Naive
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 11 Accepted Submission(s): 6
Problem Description
Rhason Cheung had a naive problem, and asked Teacher Mai for help. But Teacher Mai thought this problem was too simple, sometimes naive. So she ask you for help.
She has a tree withn vertices, numbered from 1 to n . The weight of i -th node is wi .
You need to support two kinds of operations: modification and query.
For a modification operationu,w , you need to change the weight of u -th node into w .
For a query operationu,v , you should output ∑ni=1∑nj=1f(i,j) . If there is a vertex on the path from u to v and the path from i to j in the tree, f(i,j)=wiwj , otherwise f(i,j)=0 . The number can be large, so print the number modulo 109+7
She has a tree with
You need to support two kinds of operations: modification and query.
For a modification operation
For a query operation
Input
There are multiple test cases.
For each test case, the first line contains two numbersn,m(1≤n,m≤105) .
There aren numbers in the next line, the i -th means wi(0≤wi≤109) .
Nextn−1 lines contain two numbers each, ui and vi , that means that there is an edge between ui and vi .
The following arem lines. Each line indicates an operation, and the format is "1 u w "(modification) or "2 u v "(query)(0≤w≤109)
For each test case, the first line contains two numbers
There are
Next
The following are
Output
For each test case, print the answer for each query operation.
Sample Input
6 51 2 3 4 5 61 21 32 42 54 62 3 51 5 62 2 31 1 72 2 4
Sample Output
341348612
Author
xudyh
Source
2015 Multi-University Training Contest 9
根据题意求所有i,j路径经过路径u,v上的点,那么对wi*wj累加
反面考虑:所有路径累加和 - 不经过路径的累加和
那么只需快速得到不在路径上子树的规模,他们的平方的累加和就是结果。
解题报告用的是树链剖分。我还没想好怎么实现。
比赛的时候想到LCT了,但是之前没写过用子树标记父亲的标记的代码,所以最后也没打出来。
但是之前看过别人有实现过,晚上想一想也想到了。
如何实现LCT的结点记录自己子树的信息:
用一个标记如S1,记录,这个标记只有在断开连接或者建立连接的时候才会更新。然后用一个S2,这个标记是用于splay上做更新的
于是s1的更改只需在access操作更改,而s2只需update时更新即可。
如果要用我的代码当模板注意我的注释哦。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<vector>using namespace std;#define maxn 200007#define inf 1000000000#define ll long longll mod = 1000000007;struct Node{ Node *fa,*ch[2]; bool rev,root;//基本结构不需要修改 ll val,s1,s2,s3,s4;//这里的标记可以更改};Node pool[maxn];Node *nil,*tree[maxn];int cnt = 0;void init(){ cnt = 1; nil = tree[0] = pool; nil->ch[0] = nil->ch[1] = nil; nil->s1 = nil->s2 = nil->val = nil->s3 = nil->s4 = 0;}Node *newnode(ll val,Node *f){ pool[cnt].fa = f; pool[cnt].ch[0]=pool[cnt].ch[1]=nil; pool[cnt].rev = false; pool[cnt].root = true;//以下可修改 pool[cnt].val = val; pool[cnt].s1 = 0; pool[cnt].s2 = 0; pool[cnt].s3 = 0; pool[cnt].s4 = 0; return &pool[cnt++];}//左右子树反转******真正把结点变为根void update_rev(Node *x){ if(x == nil) return ; x->rev = !x->rev; swap(x->ch[0],x->ch[1]);}//splay向上更新信息******void update(Node *x){//splay需要自己写更新代码 if(x == nil) return ; x->s2 = x->s1 + x->val; x->s4 = x->s3; if(x->ch[0] != nil){ x->s2 += x->ch[0]->s2; if(x->s2 >= mod) x->s2 -= mod; x->s4 += x->ch[0]->s4; x->s4 %= mod; } if(x->ch[1] != nil){ x->s2 += x->ch[1]->s2; if(x->s2 >= mod) x->s2 -= mod; x->s4 += x->ch[1]->s4; x->s4 %= mod; }}//splay下推信息******void pushdown(Node *x){//树的反转,才能保证把一个结点提为根。如果有其他下推操作,自己加入 if(x->rev != false){ update_rev(x->ch[0]); update_rev(x->ch[1]); x->rev = false; }}//splay在root-->x的路径下推信息******void push(Node *x){//不需要改 if(!x->root) push(x->fa); pushdown(x);}//将结点x旋转至splay中父亲的位置******void rotate(Node *x){//旋转操作,不太需要改,除非有懒标记,需要加上pushdown,update Node *f = x->fa, *ff = f->fa; int t = (f->ch[1] == x); if(f->root) x->root = true, f->root = false; else ff->ch[ff->ch[1] == f] = x; x->fa = ff; f->ch[t] = x->ch[t^1]; x->ch[t^1]->fa = f; x->ch[t^1] = f; f->fa = x; update(f);}//将结点x旋转至x所在splay的根位置******void splay(Node *x){//不需要改 push(x); Node *f, *ff; while(!x->root){ f = x->fa,ff = f->fa; if(!f->root) if((ff->ch[1]==f)&&(f->ch[1] == x)) rotate(f); else rotate(x); rotate(x); } update(x);}//将x到树根的路径并成一条path******Node *access(Node *x){ Node *y = nil,*z; while(x != nil){ splay(x); z = x->ch[1];//记录断开的结点 x->ch[1]->root = true; (x->ch[1] = y)->root = false; update(z); x->s1 += z->s2;//更新父亲信息 x->s3 += (z->s2*z->s2); x->s1 %= mod; x->s3 %= mod; x->s1 -= y->s2; x->s3 -= y->s2*y->s2; x->s1 %= mod; x->s3 %= mod; update(x); y = x; x = x->fa; } return y;}//将结点x变成树根******void be_root(Node *x){//基本操作 access(x); splay(x); update_rev(x);}int value[maxn];vector<int> head[maxn];void dfs(int u,int f){//dfs建立没有链的森林 tree[u]->fa = tree[f]; for(int i = 0;i < head[u].size() ;i++){ int v = head[u][i]; if(v == f) continue; dfs(v,u); tree[u]->s1 += tree[v]->s2; tree[u]->s1 %= mod; tree[u]->s3 += tree[v]->s2*tree[v]->s2; tree[u]->s3 %= mod; } update(tree[u]);}int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ for(int i = 1;i <= n; i++) scanf("%d",&value[i]); for(int i = 0;i <= n; i++) head[i].clear(); int u,v; for(int i = 1;i < n; i++){ scanf("%d%d",&v,&u); head[v].push_back(u); head[u].push_back(v); } init(); for(int i=1;i <= n;i++) tree[i] = newnode(value[i],nil); dfs(1,0); ll total = 0; for(int i = 1;i <= n; i++) total += value[i]; total %= mod; int t; for(int i = 0;i < m; i++){ scanf("%d%d%d",&t,&u,&v); if(t == 1){ be_root(tree[u]); access(tree[u]); total = total + v - tree[u]->val; total %= mod; tree[u]->val = v; update(tree[u]); } else { be_root(tree[u]); access(tree[v]); splay(tree[v]); ll ans = total*total%mod-tree[v]->s4; ans = (ans%mod+mod)%mod; printf("%I64d\n",ans); } } } return 0;}
0 0
- HDU 5405 Sometimes Naive 2015多校联合训练赛#9 LCT 树链剖分
- hdu 5398 GCD Tree 2015多校联合训练赛#9 LCT,动态生成树
- Hdu 5405 Sometimes Naive 树链剖分+线段树
- hdu 5326 work 搜索 2015多校联合训练赛
- hdu 5417 RGCDQ 2015多校联合训练赛
- hdu 5387 Clock 2015多校联合训练赛#8
- hdu 5406 2015 多校联合训练赛#10 dp
- hdu 5402 ,Travelling Salesman Problem,2015多校联合训练赛#9
- hdu 5399 Too Simple 2015多校联合训练赛#9 模拟
- hdu 5400 Arithmetic Sequence 2015多校联合训练赛#9 枚举
- hdu 5396 Expression 2015多校联合训练赛#9 动态规划 dp
- 多校联合训练4&&HDU 5763
- 多校联合训练7&&HDU 5810
- 多校联合训练8&&HDU 5828
- hdu 5303 Delicious Apples 2015多校联合训练赛2 dp+枚举
- hdu 5338 ZZX and Permutations 2015多校联合训练赛,贪心,线段树,树状数组
- hdu 5327 Olympiad 简单题 2015多校联合训练赛
- hdu 5328 Problem Killer 2015多校联合训练赛4 简单题
- Rectangle Area
- iOS UI初级-常用UI控件
- iOS开发中的小技巧
- linux下mysql默认安装目录和常用命令
- git 克隆远程仓库并创建分支、提交分支、获取分支
- HDU 5405 Sometimes Naive 2015多校联合训练赛#9 LCT 树链剖分
- 每天都好困的说
- 异步,线程,并行概念
- 再谈应用环境下的TIME_WAIT和CLOSE_WAIT
- Spark之WordCount
- Linux“自动备份/删除”MYSQL
- RHEL7 配置VNC远程桌面工具
- HDU 5402 Travelling Salesman Problem (2015 Multi-University Training Contest 9 2015多校联合)
- 基数排序之多关键字排序运用队列