Aragorn's Story
來源:http://120.78.128.11/Problem.jsp?pid=2710 來源:http://acm.hdu.edu.cn/showproblem.php?pid=3966
這題就是一個模板題,模板調過了就可以過(存板子)
樹鏈剖分+樹狀數組:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=50005;
int fa[N], siz[N], dep[N], son[N];
int id[N], top[N], self[N], cnt;
int sz, head[N];
int sav[N];
int n;
void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'|s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
struct Ed
{
int to, next;
}E[N*2];
void insert_E(int u, int v)
{
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz++;
}
struct SZSZ_tree
{
int sum[N];
void init()
{
Q(sum, 0);
}
int lowbit(int x)
{
return x&(-x);
}
void update(int i, int v)
{
while(i<=n)
{
sum[i]+=v;
i+=lowbit(i);
}
}
int ALL(int i)
{
int res=0;
while(i>0)
{
res+=sum[i];
i-=lowbit(i);
}
return res;
}
void updrag(int x, int y, int k)///同上寫法///表示將樹從x到y結點最短路徑上所有節點的值都加上k
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update(id[top[x]], k);
update(id[x]+1, -k);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
update(id[x], k);
update(id[y]+1, -k);
}
}tree;
void init()
{
Q(head, -1);
Q(son, 0);
tree.init();
sz=1;
cnt=0;
}
void DFS(int now, int DEP, int F)
{
fa[now]=F;
dep[now]=DEP;
siz[now]=1;
int key=-1;
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==F)
continue;
DFS(E[i].to, DEP+1, now);
siz[now]+=siz[E[i].to];
if(siz[E[i].to]>key)
son[now]=E[i].to, key=siz[E[i].to];
}
}
void DFS_(int now, int tp)
{
id[now]=++cnt;
self[cnt]=sav[now];///這個點是build線段樹用的
top[now]=tp;///按序將邊加入線段樹
if(!son[now])
return ;
DFS_(son[now], tp);///重兒子的top[]從重鏈頂端繼承
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==son[now]||E[i].to==fa[now])
continue;
DFS_(E[i].to, E[i].to);///輕兒子top[]爲自身
}
}
int main()
{
int m, r;
while(~scanf("%d%d%d", &n, &m, &r))
{
init();
for(int i=1; i<=n; i++)
read(sav[i]), tree.sum[i]=0;
while(m--)
{
int a, b;
read(a), read(b);
insert_E(a, b);
insert_E(b, a);
}
DFS(1, 1, 0);
DFS_(1, 1);
while(r--)
{
char op[33];
int x, y, z;
scanf("%s", op);
read(x);
if(op[0]=='I')
read(y), read(z), tree.updrag(x, y, z);
else if(op[0]=='D')
read(y), read(z), tree.updrag(x, y, -z);
else
printf("%d\n", tree.ALL(id[x])+sav[x]);
}
}
return 0;
}
樹鏈剖分+線段樹:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define mid ((node[now].l+node[now].r)>>1)
#define lson node[now].l, mid, now<<1
#define rson mid+1, node[now].r, now<<1^1
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=50505;
const int INF=0x3f3f3f3f;
typedef int mint;
mint fa[N], siz[N], dep[N], son[N];
mint id[N], top[N], self[N], cnt;
/**
siz[u] 保存以u爲根的子樹節點個數
top[u] 保存當前節點所在鏈的頂端節點
son[u] 保存重兒子
dep[u] 保存結點u的深度值
fa[u] 保存結點u的父親節點
id[u] 保存樹中每個節點剖分以後的新編號(DFS的執行順序)
self[u] 保存當前節點在樹中的位置
**/
mint sz, head[N];
mint sav[N];
mint n, mod;
void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'|s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
mint Max(mint a, mint b)
{ return a>b?a:b; }
mint Min(mint a, mint b)
{ return a<b?a:b; }
struct Ed
{
int to, next;
}E[N*2];
void insert_E(int u, int v)
{
E[sz].to=v;
E[sz].next=head[u];
head[u]=sz++;
}
struct No
{
mint ret;
struct no
{
mint l, r, sum, mins, maxn, lazy, lazyset;
}node[N<<2];
void build(int L, int R, int now)///建樹
{
node[now].lazy=0;
node[now].lazyset=0;
node[now].l=L;
node[now].r=R;
if(L==R)
node[now].mins=node[now].maxn=node[now].sum=self[L];
else
{
build(L, mid, now<<1);
build(mid+1, R, now<<1^1);
pushup(now);
}
}
void pushup(int now)
{
node[now].sum=node[now<<1].sum+node[now<<1^1].sum;
node[now].maxn=Max(node[now<<1].maxn, node[now<<1^1].maxn);
node[now].mins=Min(node[now<<1].mins, node[now<<1^1].mins);
}
void pushdown(int now)
{
if (node[now].lazy)
{
int len=node[now].r-node[now].l+1;
node[now<<1].lazy+=node[now].lazy;
node[now<<1^1].lazy+=node[now].lazy;
node[now<<1].sum+=node[now].lazy*(len-(len>>1));
node[now<<1^1].sum+=node[now].lazy*(len>>1);
node[now<<1].maxn+=node[now].lazy;
node[now<<1^1].maxn+=node[now].lazy;
node[now<<1].mins+=node[now].lazy;
node[now<<1^1].mins+=node[now].lazy;
node[now].lazy=0;
}
}
void pushdown_set(int now)
{
if (node[now].lazyset)
{
int len=node[now].r-node[now].l+1;
node[now<<1].lazyset=node[now].lazyset;
node[now<<1^1].lazyset=node[now].lazyset;
node[now<<1].sum=node[now].lazyset*(len-(len>>1));
node[now<<1^1].sum=node[now].lazyset*(len>>1);
node[now<<1].maxn=node[now].lazyset;
node[now<<1^1].maxn=node[now].lazyset;
node[now<<1].mins=node[now].lazyset;
node[now<<1^1].mins=node[now].lazyset;
node[now].lazyset=0;
}
}
void update(int L, int R, mint v, int now)///區間更新
{
if(L<=node[now].l&&node[now].r<=R)
{
node[now].lazy+=v;
node[now].sum+=(node[now].r-node[now].l+1)*v;
node[now].maxn+=v;
node[now].mins+=v;
return ;
}
pushdown(now);
if(L<=mid)
update(L, R, v, now<<1);
if(R>mid)
update(L, R, v, now<<1^1);
pushup(now);
}
mint query(int L, int R, int now)///區間求和
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].sum;
pushdown(now);
mint ret=0;
if(L<=mid)
ret+=query(L, R, now<<1);
if(R>mid)
ret+=query(L, R, now<<1^1);
return ret;
}
void addn(int now)///將1~n的節點裏的值保存到一個sav[]數組裏
{
for(mint i=node[now].l; i<=node[now].r; i++)
sav[i]+=node[now].sum;
if(node[now].l==node[now].r)
return;
addn(now<<1);
addn(now<<1^1);
}
mint querymin(int L,int R,int now)///L~R的最小值
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].mins;
pushdown(now);
if(L<=mid)
ret=Min(ret, querymin(L,R,now<<1));
if(R>mid)
ret=Min(ret, querymin(L,R,now<<1^1));
return ret;
}
mint querymax(int L,int R,int now)///L~R的最大值
{
if(L<=node[now].l&&R>=node[now].r)
return node[now].maxn;
pushdown(now);
if(L<=mid)
ret=Max(ret, querymax(L,R,now<<1));
if(R>mid)
ret=Max(ret, querymax(L,R,now<<1^1));
return ret;
}
void print(int now)///輸出所有葉子節點
{
if(node[now].l==node[now].r)
printf("%lld ", node[now].sum);
else
{
print(now<<1);
print(now<<1^1);
}
}
mint getsum(int x, int y)///表示求樹從x到y結點最短路徑上所有節點的值之和
{
mint ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);///把x點改爲所在鏈頂端的深度更深的那個點
ans+=query(id[top[x]], id[x], 1);///一條鏈一條鏈的求和
x=fa[top[x]];///往高處跑
}
if(dep[x]>dep[y])
swap(x, y);
return ans+query(id[x], id[y], 1);
}
void updrag(int x, int y, mint k)///同上寫法///表示將樹從x到y結點最短路徑上所有節點的值都加上k
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
update(id[top[x]], id[x], k, 1);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
update(id[x], id[y], k, 1);
}
mint qson(int x)///表示求以x爲根節點的子樹內所有節點值之和
{
ret=0;
query(id[x], id[x]+siz[x]-1, 1);///他有siz[x]-1個子節點;
return ret;
}
void updson(int x, int k)///表示將以x爲根節點的子樹內所有節點值都加上k
{
update(id[x], id[x]+siz[x]-1, k, 1);
}
}tree;
void init()
{
Q(head, -1);
Q(son, 0);
sz=1;
cnt=0;
}
void DFS(int now, int DEP, int F)
{
fa[now]=F;
dep[now]=DEP;
siz[now]=1;
int key=-1;
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==F)
continue;
DFS(E[i].to, DEP+1, now);
siz[now]+=siz[E[i].to];
if(siz[E[i].to]>key)
son[now]=E[i].to, key=siz[E[i].to];
}
}
void DFS_(mint now, mint tp)
{
id[now]=++cnt;
self[cnt]=sav[now];///這個點是build線段樹用的
top[now]=tp;///按序將邊加入線段樹
if(!son[now])
return ;
DFS_(son[now], tp);///重兒子的top[]從重鏈頂端繼承
for(int i=head[now]; ~i; i=E[i].next)
{
if(E[i].to==son[now]||E[i].to==fa[now])
continue;
DFS_(E[i].to, E[i].to);///輕兒子top[]爲自身
}
}
int main()
{
mint m, r;
while(~scanf("%d%d%d", &n, &m, &r))
{
init();
for(int i=1; i<=n; i++)
read(sav[i]);
while(m--)
{
int a, b;
read(a), read(b);
insert_E(a, b);
insert_E(b, a);
}
DFS(1, 1, 0);
DFS_(1, 1);
tree.build(1, n, 1);
while(r--)
{
char op[33];
int x, y, z;
scanf("%s", op);
read(x);
if(op[0]=='I')
read(y), read(z), tree.updrag(x, y, z);
else if(op[0]=='D')
read(y), read(z), tree.updrag(x, y, -z);
else
printf("%d\n", tree.getsum(x, x));
}
}
return 0;
}