CSU 1607: Do You Have The Template?(树链剖分)边权

来源:互联网 发布:union软件安卓版 编辑:程序博客网 时间:2024/04/30 04:52

1607: Do You Have The Template?

Time Limit: 7 Sec  Memory Limit: 128 MB
Submit: 112  Solved: 8
[Submit][Status][Web Board]

Description

There is a tree with N vertices, each edges have a positive length.
And here comes 4 operations,
0 a b, means query the maximum length and the sum of length on the path between vertex a and vertex b.
1 a b, means change the a-th edge's length to b.
2 a b 0 c, means change all edges' length on the path between vertex a and vertex b to c.
2 a b 1 c, means add all edges' length on the path between vertex a and vertex b by c.

Input

There're several cases.
The first line contains a positive integer N (2 <= N <= 10000), meaning there're N vertices, marked 1 to N. Then N – 1 lines follow with the i-th line describing the i-th edge. Each line contains three integers a b c, meaning there is an edge between vertex a and vertex b with the length of c.
Then one integer M (M <= 10000), means there're M queries. And followed by M lines, each line will contain one operation described as above.

Output

For each 0 a b query, you should output the maximum length and the sum.
The data insure no number will be bigger than 2^31.

Sample Input

41 2 12 3 22 4 3100 1 30 1 40 3 41 2 30 1 32 4 3 0 20 1 42 4 3 1 20 1 30 1 4

Sample Output

2 33 43 53 42 34 54 5
题意:给出一棵树有n个节点,每个边有权值,现在有M个操作:
0 a b 表示输出从a点到b点的路径的边权最大值和边树总和。
1 a b 表示第a条边的权值变为b
2 a b 0 c 表示从a点到b点的路径的每条边权都变成c
2 a b 1 c 表示从a点到b点的路径的每条边权都加上c
坑点:在CSU的这道题用vector建图就WA。标程代码有漏洞,就是用root[k].toc去判断是否需要更新线段树中k的左右子节点。
解题:用树链剖分,边权变点权。用线段树去维护边权。
#include<stdio.h>#include<string.h>#include<vector>const int N=10015;using namespace std; int head[N], to[N << 1], next1[N << 1], tot;int top[N];    //top[v]=u表示点v,u在一个链中,且u是这个链深度最小的点(即顶端)int fath[N];   //记录父节点int deep[N];   //每个点在树上的深度int num[N];    //每棵子树的节点个数int son[N];    //选的重边子节点int p[N];      //树上每个点在线段树中所对应的点int pos; void addEdge(const int& u, const int& v) {  to[tot] = v, next1[tot] = head[u], head[u] = tot++;} void addUndirEdge(const int& u, const int& v) {  addEdge(u, v), addEdge(v, u);} void init(int n){    pos=0; tot=0;    memset(son,-1,sizeof(son));    memset(head,-1,sizeof(head));}void dfs1(int u,int pre,int d){    deep[u]=d; fath[u]=pre; num[u]=1;    for (int i = head[u]; i != -1; i = next1[i]) {    int v = to[i];        if(v==pre)continue;        dfs1(v,u,d+1);        num[u]+=num[v];        if(son[u]==-1||num[v]>num[son[u]])            son[u]=v;    }}void getpos(int u,int root){    top[u]=root;    p[u]=pos++;    if(son[u]==-1)        return ;    getpos(son[u],root);    for (int i = head[u]; i != -1; i = next1[i]) {    int v = to[i];        if(son[u]!=v&&v!=fath[u])            getpos(v,v);    }} //线段树struct tree{    int sum,maxv,toc,addc; }root[N*4];int val[N];int MAX(int a,int b){    return a>b?a:b;}void build(int l,int r,int k){    int mid=(l+r)/2;    root[k].addc=0;    root[k].toc=0;    if(l==r){        root[k].sum=root[k].maxv=val[l]; return ;    }    build(l,mid,k<<1);    build(mid+1,r,k<<1|1);    root[k].sum=root[k<<1].sum+root[k<<1|1].sum;    root[k].maxv=MAX(root[k<<1].maxv,root[k<<1|1].maxv);}void upson(int k,int l,int r){    int mid=(l+r)/2;    if(root[k].toc)    {        root[k<<1].sum=(mid-l+1)*root[k].toc;        root[k<<1].maxv=root[k].toc;        root[k<<1].toc=root[k].toc;        root[k<<1].addc=0;         root[k<<1|1].sum=(r-mid)*root[k].toc;        root[k<<1|1].maxv=root[k].toc;        root[k<<1|1].toc=root[k].toc;        root[k<<1|1].addc=0;        root[k].toc=0;    }     if(root[k].addc)    {        root[k<<1].sum+=(mid-l+1)*root[k].addc;        root[k<<1].maxv+=root[k].addc;        root[k<<1].addc+=root[k].addc;         root[k<<1|1].sum+=(r-mid)*root[k].addc;        root[k<<1|1].maxv+=root[k].addc;        root[k<<1|1].addc+=root[k].addc;        root[k].addc=0;    }}void updata1(int l,int r,int k,const int L,const int R,int c){    if(L<=l&&r<=R)    {        root[k].sum=(r-l+1)*c; root[k].maxv=c;        root[k].toc=c; root[k].addc=0;        return ;    }    int mid=(l+r)/2;    upson(k,l,r);     if(L<=mid)        updata1(l,mid,k<<1,L,R,c);    if(mid<R)        updata1(mid+1,r,k<<1|1,L,R,c);    root[k].sum=root[k<<1].sum+root[k<<1|1].sum;    root[k].maxv=MAX(root[k<<1].maxv,root[k<<1|1].maxv);}void updata2(int l,int r,int k, int L, int R,int c){    if(L<=l&&r<=R)    {        root[k].sum+=(r-l+1)*c; root[k].maxv+=c;        root[k].addc+=c;        return ;    }    int mid=(l+r)/2;    upson(k,l,r);     if(L<=mid)        updata2(l,mid,k<<1,L,R,c);    if(mid<R)        updata2(mid+1,r,k<<1|1,L,R,c);    root[k].sum=root[k<<1].sum+root[k<<1|1].sum;    root[k].maxv=MAX(root[k<<1].maxv,root[k<<1|1].maxv);}int sum,maxv;void query(int l,int r,int k,int L,int R){    if(L<=l&&r<=R)    {        sum+=root[k].sum;        maxv=MAX(maxv,root[k].maxv);        return ;    }    int mid=(l+r)/2;    upson(k,l,r);     if(L<=mid)        query(l,mid,k<<1,L,R);    if(mid<R)        query(mid+1,r,k<<1|1,L,R);}void swp(int &a,int &b){    int tt;    tt=a; a=b; b=tt;}void Operat0(int u,int v){    int f1=top[u], f2=top[v];    sum=0; maxv=0;    while(f1!=f2)    {        if(deep[f1]<deep[f2])        {            swp(f1,f2); swp(u,v);        }        query(1,pos,1,p[f1],p[u]);        u=fath[f1]; f1=top[u];    }    if(u==v) return ;    if(deep[u]>deep[v])swp(u,v);    query(1,pos,1,p[son[u]],p[v]);}void Operat1(int u,int v,int c){    int f1=top[u], f2=top[v];    while(f1!=f2)    {        if(deep[f1]<deep[f2])        {            swp(f1,f2); swp(u,v);        }        updata1(1,pos,1,p[f1],p[u],c);        u=fath[f1]; f1=top[u];    }    if(u==v) return ;    if(deep[u]>deep[v])swp(u,v);    updata1(1,pos,1,p[son[u]],p[v],c);}void Operat2(int u,int v,int c){    int f1=top[u], f2=top[v];    while(f1!=f2)    {        if(deep[f1]<deep[f2])        {            swp(f1,f2); swp(u,v);        }        updata2(1,pos,1,p[f1],p[u],c);        u=fath[f1]; f1=top[u];    }    if(u==v) return ;    if(deep[u]>deep[v])swp(u,v);    updata2(1,pos,1,p[son[u]],p[v],c);} struct EDG{    int u,v,c;}edg[N];int main(){    int n,q,op,a,b;    while(scanf("%d",&n)!=EOF)    {        init(n);        for(int i=1;i<n;i++)        {            scanf("%d%d%d",&edg[i].u,&edg[i].v,&edg[i].c);            addUndirEdge(edg[i].u, edg[i].v);        }         dfs1(1,1,1);        getpos(1,1);        pos=n;        for(int i=1;i<n;i++)        {            if(deep[edg[i].u]>deep[edg[i].v])                edg[i].v=edg[i].u;            val[p[edg[i].v]]=edg[i].c;        }        build(1,pos,1);         scanf("%d",&q);        while(q--)        {            scanf("%d%d%d",&op,&a,&b);            if(op==0)            {                Operat0(a,b);                printf("%d %d\n",maxv,sum);            }            else if(op==1)                updata1(1,pos,1,p[edg[a].v],p[edg[a].v],b);            else            {                int tt,c;                scanf("%d%d",&tt,&c);                if(tt==0)                    Operat1(a,b,c);                else                    Operat2(a,b,c);            }        }    }} /**************************************************************    Problem: 1607    User: aking2015    Language: C++    Result: Accepted    Time:912 ms    Memory:2180 kb****************************************************************/


0 0