树的统计Count bzoj 1036 树链剖分+线段树

题目大意

给出一棵树,每个节点有一个初始权值。要求资瓷三个操作:
CHANGE x y把节点的权值变为y
QMAX x y求x到y的路径上的最大值
QSUM x y求x到y的路径上的和

分析

因为感兴趣,所以学习了树链剖分。
但是发现这是一个巨坑啊!!!
打了大概2个半小时的代码,真真正正的码字题。
原理很简单,可以见这位大牛大博客——传送门

ps:模板+1

code

#include
#include
#include
#include
#include
#include
#define maxn 30005  
#define maxm 60005 
#define INF 0x7fffffff;
using namespace std;

struct gg{
    int x,y,w;
    int next;
}edge[maxm];
int ls[maxn];
int edge_m;

struct arr{
    int x,y;
    int sum;      
    int mx;
}f[maxm*6];

int a[maxn];
int n,m;

void swap1(int &x,int &y)
{
    int z;
    z=x; x=y; y=z;
    return;
}

void add(int x,int y)
{
    edge_m++;
    edge[edge_m].x=x; edge[edge_m].y=y; edge[edge_m].next=ls[x]; ls[x]=edge_m;
    edge_m++;
    edge[edge_m].x=y; edge[edge_m].y=x; edge[edge_m].next=ls[y]; ls[y]=edge_m;
    return;
}

int insert(int r,int x,int y,int add)//线段树修改操作。
{
    if ((f[r].x==x)&&(f[r].y==y)) 
    {
        f[r].sum=f[r].mx=add;
        return 0;
    }
    int mid=(f[r].x+f[r].y)/2;
    if (y<=mid) insert(r*2,x,y,add);
        else if (x>mid) insert(r*2+1,x,y,add);
            else insert(r*2,x,mid,add),insert(r*2+1,mid+1,y,add);
    f[r].sum=f[r*2].sum+f[r*2+1].sum;
    f[r].mx=max(f[r*2].mx,f[r*2+1].mx);
}

int maketree(int r,int x,int y)//建树
{
    f[r].x=x; f[r].y=y; 
    f[r].sum=0; f[r].mx=0;
    if (x==y) return 0;
    int mid=(x+y)/2;
    maketree(r*2,x,mid);
    maketree(r*2+1,mid+1,y);
}

int siz[maxn],dep[maxn],top[maxn],fa[maxn],son[maxn],w[maxn];

void dfs1(int x,int r)
{
    fa[x]=r;
    siz[x]=1;
    dep[x]=dep[r]+1;
    int mx=0;
    for (int i=ls[x];i;i=edge[i].next)
    {
        if (edge[i].y==r) continue;
        dfs1(edge[i].y,x);
        siz[x]+=siz[edge[i].y];
        if (mxy])
        {
            mx=siz[edge[i].y];
            son[x]=edge[i].y;
        }
    }
    return;
}

int num=0;

void dfs2(int x,int st)
{
    num++;
    w[x]=num; top[x]=st;
    if (son[x]!=0)  dfs2(son[x],st);
    for (int i=ls[x];i;i=edge[i].next)
        if ((edge[i].y!=fa[x])&&(edge[i].y!=son[x]))
            dfs2(edge[i].y,edge[i].y);
    return;
}

int findmax(int r,int x,int y)
{
    if ((f[r].x==x)&&(f[r].y==y)) return f[r].mx;
    int mid=(f[r].x+f[r].y)/2;
    if (y<=mid) return findmax(r*2,x,y);
        else if (x>mid) return findmax(r*2+1,x,y);
            else return max(findmax(r*2,x,mid),findmax(r*2+1,mid+1,y));
}

int findsum(int r,int x,int y)
{
    if ((f[r].x==x)&&(f[r].y==y)) return f[r].sum;
    int mid=(f[r].x+f[r].y)/2;
    if (y<=mid) return findsum(r*2,x,y);
        else if (x>mid) return findsum(r*2+1,x,y);
            else return findsum(r*2,x,mid)+findsum(r*2+1,mid+1,y);
}

int solvemax(int x,int y)
{
    int mx=-INF;
    int f1=top[x];
    int f2=top[y];
    while (f1!=f2)
    {
        if (dep[f1]x,y); swap1(f1,f2);};
        mx=max(mx,findmax(1,w[f1],w[x]));
        x=fa[f1]; f1=top[x];
    }
    if (dep[x]>dep[y]) swap1(x,y);
    mx=max(mx,findmax(1,w[x],w[y]));
    return mx;
}

int solvesum(int x,int y)
{
    int mx=0;
    int f1=top[x];
    int f2=top[y];
    while (f1!=f2)
    {
        if (dep[f1]x,y); swap1(f1,f2);};
        mx+=findsum(1,w[f1],w[x]);
        x=fa[f1]; f1=top[x];
    }
    if (dep[x]>dep[y]) swap1(x,y);
    mx+=findsum(1,w[x],w[y]);
    return mx;
}

void init()
{
    scanf("%d",&n);
    for (int i=1;iint x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
}

int main()
{
    init();
    maketree(1,1,maxm*2);
    dfs1(1,0);
    dfs2(1,1);
    for (int ii=1;ii<=n;ii++)
        insert(1,w[ii],w[ii],a[ii]);
    scanf("%d",&m);
    char c[10];
    int x,y;
    for (int i=1;i<=m;i++)
    {
        scanf("%s%d%d",c,&x,&y);
        if (c[0]=='C') 
            insert(1,w[x],w[x],y);
        else
            if (c[1]=='M')
                printf("%d\n",solvemax(x,y));
            else 
                printf("%d\n",solvesum(x,y));
    }
    return 0;
}

你可能感兴趣的:(c++,树链剖分)