Tree
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 4414 Accepted Submission(s): 847
Problem Description
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N
There are N - 1 edges numbered from 1 to N - 1.
Each node has a value and each edge has a value. The initial value is 0.
There are two kind of operation as follows:
● ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k.
● ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k.
After finished M operation on the tree, please output the value of each node and edge.
There are N - 1 edges numbered from 1 to N - 1.
Each node has a value and each edge has a value. The initial value is 0.
There are two kind of operation as follows:
● ADD1 u v k: for nodes on the path from u to v, the value of these nodes increase by k.
● ADD2 u v k: for edges on the path from u to v, the value of these edges increase by k.
After finished M operation on the tree, please output the value of each node and edge.
Input
The first line of the input is T (1 ≤ T ≤ 20), which stands for the number of test cases you need to solve.
The first line of each case contains two integers N ,M (1 ≤ N, M ≤10 5),denoting the number of nodes and operations, respectively.
The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.
For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -10 5 ≤ k ≤ 10 5)
The first line of each case contains two integers N ,M (1 ≤ N, M ≤10 5),denoting the number of nodes and operations, respectively.
The next N - 1 lines, each lines contains two integers u, v(1 ≤ u, v ≤ N ), denote there is an edge between u,v and its initial value is 0.
For the next M line, contain instructions “ADD1 u v k” or “ADD2 u v k”. (1 ≤ u, v ≤ N, -10 5 ≤ k ≤ 10 5)
Output
For each test case, print a line “Case #t:”(without quotes, t means the index of the test case) at the beginning.
The second line contains N integer which means the value of each node.
The third line contains N - 1 integer which means the value of each edge according to the input order.
The second line contains N integer which means the value of each node.
The third line contains N - 1 integer which means the value of each edge according to the input order.
Sample Input
2 4 2 1 2 2 3 2 4 ADD1 1 4 1 ADD2 3 4 2 4 2 1 2 2 3 1 4 ADD1 1 4 5 ADD2 3 2 4
Sample Output
Case #1: 1 1 0 1 0 2 2 Case #2: 5 0 0 5 0 4 0
题意:
给你一棵树,树上的点权值,边权值都是0,有两种操作
1 将x->y的路径上的点的权值都+k
2 将x->y的路径上的边的权值都+k
解析:
这里树链剖分,只不过不能套线段树了,因为会超时,要使用更新连续区间一个小的技巧
当更新[x,y]区间+k,就将sum[x]+=k,sum[y+1]-=k
举例
一个一开始全为0的序列,有2个操作,[3,5]全+3,[5,7]全+6
这样用上述的方法,在最后i从2开始sum[i]+=sum[i-1],就可以得到答案了
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long int lli;
const int MAXN = 1e5+10;
#define INF 1223372036854775807
#define M(a) memset(a,0,sizeof(a))
int val[MAXN],fa[MAXN],dep[MAXN],siz[MAXN],id[MAXN],top[MAXN],ran[MAXN],son[MAXN];
typedef struct ee
{
int u,v;
int next;
}ee;
ee edge[MAXN*2];
int head[MAXN],cnt;
int num,n;
typedef struct node
{
int ii;
lli eV;
lli nV;
}node;
int fnum[MAXN];
void addedge(int u,int v)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void dfs1(int x,int f,int d)
{
dep[x]=d;
siz[x]=1;
son[x]=0;
fa[x]=f;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int tmp=edge[i].v;
if(tmp==f) continue;
dfs1(tmp,x,d+1);
siz[x]+=siz[tmp];
if(siz[son[x]]<siz[tmp])
{
son[x]=tmp;
}
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
id[x]=++num;
ran[num]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=edge[i].next)
{
int tmp=edge[i].v;
if(tmp==fa[x]||tmp==son[x]) continue;
dfs2(tmp,tmp);
}
}
lli sum1[MAXN],sum2[MAXN];
void solve1(int a,int b,lli c)
{
if(dep[top[a]]<dep[top[b]])
{
swap(a,b);
}
while(top[a]!=top[b])
{
//int tmp=top[a];
//updateN(1,1,n,id[top[a]],id[a],c);
sum1[id[top[a]]]+=c;
sum1[id[a]+1]-=c;
a=fa[top[a]];
if(dep[top[a]]<dep[top[b]])
{
swap(a,b);
}
}
if(id[a]>id[b]) swap(a,b);
//updateN(1,1,n,id[a],id[b],c);
sum1[id[a]]+=c;
sum1[id[b]+1]-=c;
}
void solve2(int a,int b,lli c) //改边
{
if(dep[top[a]]<dep[top[b]])
{
swap(a,b);
}
while(top[a]!=top[b])
{
//int tmp=top[a];
//updateE(1,1,n,id[top[a]],id[a],c);
sum2[id[top[a]]]+=c;
sum2[id[a]+1]-=c;
a=fa[top[a]];
if(dep[top[a]]<dep[top[b]])
{
swap(a,b);
}
}
if(a==b) return;
if(id[a]>id[b]) swap(a,b);
//updateE(1,1,n,id[son[a]],id[b],c);
sum2[id[son[a]]]+=c; //对LCA代表的那条边不做改动
sum2[id[b]+1]-=c;
}
int main()
{
int q,t;
int cas=0;
scanf("%d",&t);
while(t--)
{
cas++;
scanf("%d%d",&n,&q);
num=0;
M(sum1),M(sum2);
M(son);
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
for(int i=0;i<cnt;i+=2)
{
if(dep[edge[i].u]>dep[edge[i].v]) swap(edge[i].u,edge[i].v);
fnum[i/2]=id[edge[i].v];
}
int a,b;
lli c;
char mode[10];
for(int i=0;i<q;i++)
{
scanf("%s%d%d%lld",mode,&a,&b,&c);
if(!strcmp("ADD1",mode))
{
solve1(a,b,c);
}
else
{
solve2(a,b,c);
}
}
for(int i=2;i<=n;i++)
{
sum1[i]+=sum1[i-1];
sum2[i]+=sum2[i-1];
}
printf("Case #%d:\n",cas);
for(int i=1;i<=n;i++)
{
if(i==1) printf("%lld",sum1[id[i]]);
else printf(" %lld",sum1[id[i]]);
}
printf("\n");
for(int i=0;i<n-1;i++)
{
if(i==0) printf("%lld",sum2[fnum[i]]);
else printf(" %lld",sum2[fnum[i]]);
}
printf("\n");
}
return 0;
}