SCUOJ4549-树链剖分(区间查询,区间更新,边权)

来源:互联网 发布:api管理 知乎 编辑:程序博客网 时间:2024/06/05 16:21

传送门:scu4559


Description

There is a king who is very rich, but he is very stingy. In his kingdom, there are many cities. He built many highways to connect all the cities. Buecause of his meanness, he would not build extra highways, that's to say, there is only one path between any two cities. After building all the highways, he set a high toll for each highway. But because of his greed, he sometimes will increase the tolls to get more benefits. Now the king wants to know the tolls between two cities.However he is a fool, so he asks you to help him calculate the answer.

Input

The first line contains an integer T indicating the number of cases. (T < 20)For each case, the first line contains two integers N and M indicating the number of cities and the number of operations. (N <= 10^5, M <= 10^5)Then N-1 lines followed. Each line contains three integers a, b and c. It means there is a highway between city a and city b, and the toll is c. (1 <= a <= n, 1 <= b <= n, a <> b, 0 < c <= 10^5)Then M lines followed. Each line has one of two operations.The first operation is "ADD a b c". which means adding c to the toll of every highway between city a and city b. (0 < c <= 10^5)The second is "QUERY a b", which means querying the highway tolls between city a and city b.

Output

Answer for each QUERY operation.

Sample Input

15 31 2 11 3 22 4 32 5 4QUERY 1 2ADD 1 5 1QUERY 1 5

Sample Output

17


第一道树链剖分入门题,,哎,,搞了两天,,真心菜,,树链剖分详见各路大神的博客


题目大意:


给你一个n个点的树,q次操作,每条边都有一个权值,有两种操作

1,QUERY x  y 查询 x到y的路径上所有的边权和

2,ADD x y w 将x到y的路径上的所有边权加上 w


题目思路:


树链剖分+线段树模板

基于边权的区间查询和区间更新


AC代码:


#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<vector>using namespace std;#define ll long long#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1const int maxn = 1e5+10;struct Tree{    int l,r;    ll sum,c;}node[maxn*8];    //线段树struct nod{    int v,nex;    ll w;}edge[maxn<<1];   //图;int head[maxn];int tim ;   //记录编号ll val[maxn];int Size[maxn];  // 以x为根的子树节点个数int Top[maxn];  // 当前节点所在链的顶端节点int Son[maxn];  // 保存重儿子int Deep[maxn];  // 节点深度int Father[maxn];  // 保存父亲节点int Tid[maxn];  // 剖分后的新编号int Rank[maxn];  // 保存在线段树中的编号int n,m,e;   //节点个数和边数// 初始化函数void init(){    tim = 0;    e = 1;    memset(head,-1,sizeof(head));    memset(Son,-1,sizeof(Son));}void add(int u,int v,ll w){    edge[e].v = v,edge[e].w = w,edge[e].nex = head[u],head[u]=e++;}//   记录所有的重边void dfs(int u,int father,int d){    Deep[u]=d;    Father[u]=father;    Size[u]=1;    for(int i=head[u];~i;i=edge[i].nex)    {        int v = edge[i].v;        if(v!=father)        {            val[v] = edge[i].w;            dfs(v,u,d+1);            Size[u]+=Size[v];            if(Son[u]==-1||Size[v]>Size[Son[u]])                Son[u]=v;        }    }}//重连边成重边void Create(int u,int top){    Top[u]=top;    Tid[u]=++tim;    Rank[Tid[u]] = u;    if(Son[u]==-1)return ;    Create(Son[u],top);    for(int i=head[u];~i;i=edge[i].nex)    {        int v = edge[i].v;        if(v!=Son[u]&&v!=Father[u])            Create(v,v);    }}void BuildTree(int l,int r,int rt){    node[rt].l = l,node[rt].r = r;    node[rt].c = 0;    if(l==r)    {        node[rt].sum = val[Rank[l]];        return ;    }    int mid = (l+r)>>1;    BuildTree(lson);    BuildTree(rson);    node[rt].sum = node[rt<<1].sum+node[rt<<1|1].sum;}void pushdown(int rt,ll m){    node[rt<<1].c+=node[rt].c;    node[rt<<1|1].c+=node[rt].c;    node[rt<<1].sum+=node[rt].c*(m-m/2);    node[rt<<1|1].sum+=node[rt].c*(m/2);    node[rt].c = 0;}ll quary(int l,int r,int rt)    //区间查询{    if(l<=node[rt].l&&r>=node[rt].r)return node[rt].sum;    if(node[rt].c)pushdown(rt,node[rt].r-node[rt].l+1ll);    int mid = (node[rt].l+node[rt].r)>>1;    ll res = 0;    if(l<=mid)res+=quary(l,r,rt<<1);    if(r>mid)res+=quary(l,r,rt<<1|1);    return res;}void update(int l,int r,ll w,int rt)    //区间更新{    if(l<=node[rt].l&&r>=node[rt].r)    {        node[rt].c+=w;        node[rt].sum+=(node[rt].r-node[rt].l+1ll)*w;        return ;    }    int mid = (node[rt].l+node[rt].r)>>1;    if(node[rt].c)pushdown(rt,node[rt].r-node[rt].l+1ll);    if(l<=mid)update(l,r,w,rt<<1);    if(r>mid)update(l,r,w,rt<<1|1);    node[rt].sum = node[rt<<1].sum+node[rt<<1|1].sum;}ll SUM(int x,int y){    ll res = 0;    while(Top[x]!=Top[y])    {        if(Deep[Top[x]]<Deep[Top[y]])swap(x,y);        res+=quary(Tid[Top[x]],Tid[x],1);        x = Father[Top[x]];    }    if(x!=y)    {        if(Deep[x]<Deep[y])swap(x,y);        res+=quary(Tid[y]+1,Tid[x],1);    }    return res;}void ADD(int x,int y,ll w){    while(Top[x]!=Top[y])    {        if(Deep[Top[x]]<Deep[Top[y]])swap(x,y);        update(Tid[Top[x]],Tid[x],w,1);        x = Father[Top[x]];    }    if(x!=y)    {        if(Deep[x]<Deep[y])swap(x,y);        update(Tid[y]+1,Tid[x],w,1);    }}int main(){    int t;cin>>t;    while(t--)    {        init();        scanf("%d%d",&n,&m);        for(int i=1;i<n;i++)        {            int x,y;            ll w;            scanf("%d%d%lld",&x,&y,&w);            add(x,y,w);            add(y,x,w);        }        dfs(1,1,1);        Create(1,1);        BuildTree(1,n,1);        char s[10];        while(m--)        {            scanf("%s",s);            int x,y;            ll w;            scanf("%d%d",&x,&y);            if(s[0]=='Q')            {                printf("%lld\n",SUM(x,y));            }            else            {                scanf("%lld",&w);                ADD(x,y,w);            }        }    }    return 0;}








0 0
原创粉丝点击