HDU 5405(树链剖分)

(http://acm.hust.edu.cn/vjudge/contest/view.action?cid=106364#problem/D)
题意:一棵树,点权值,两种操作,1.修改u的权值成w,2.查询u,v,求w[i]*w[j],i,j满足i,j的路径与u,v相交。
解法:先求不相交的。
对于每个节点u , 记录两个值
1. sum[u] u子树w之和。
2. sim( sum[v]^2 ) v是u的轻儿子。
每次修改操作时,对1进行区间更新,更改的2的个数最多为lg(n)个,暴力更改。
每次查询操作,区间查询2,单点查询1,即可完成操作。
总结:感觉这种只记录轻儿子还是很套路的。


//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
#include 
#include 
//#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define inf 1e9
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }
#define clr(x, y) memset(x, y, sizeof x)
#define ll long long
#define ull unsigned long long
#define FOR(i,a,b) \
    for(i=a;a=b;aint maxn = 1e5 + 30;
const int mod = 1e9+7;
struct sad{
    int to,next;
}G[maxn<<1];
int h[maxn],si;
void add(int u,int v){
//  printf("u %d v %d\n",u,v);
    G[si].to=v;
    G[si].next=h[u];
    h[u]=si++;
}
int siz[maxn],dep[maxn];
int fa[maxn],son[maxn],top[maxn];
void dfs1(int u,int f,int d){
    fa[u]=f;
    dep[u]=d;
    siz[u]=1;
    son[u]=-1;
    for(int i=h[u];~i;i=G[i].next)
    {
        int v = G[i].to;
        if(v^f){
            dfs1(v,u,d+1);
            siz[u]+=siz[v];
            if( son[u] == -1 || siz[son[u]] < siz[v] )
                son[u] = v;
        }
    }
}
int p[maxn],fp[maxn],pos;
void dfs2(int u,int sf){
//  printf("u %d sf %d son %d\n",u,sf,son[u]);
    //if( u == 0 ) while(1);
    top[u] = sf;
    p[u] = pos++;
    fp[p[u]]=u;
    if(son[u]==-1) return ;
    dfs2(son[u],sf);
    for(int i=h[u];~i;i=G[i].next)
    {
        int v=G[i].to;
//      debug(v);
        if(son[u]!=v&&fa[u]!=v)
            dfs2(v,v);
    }
}

int rs[maxn];
void upp(int x,int p)
{
    while(x<=pos)
    {
        rs[x] = ((rs[x]+p)%mod+mod)%mod;
        x+=x&-x;
    }
}
int get(int x)
{
    int ret = 0;
    while(x)
    {
        ret = (ret+rs[x])%mod;
        x-=x&-x;
    }
    return ret;
}


int rs2[maxn];
void upp2(int x,int p)
{
    while(x<=pos)
    {
        rs2[x] = ((rs2[x]+p)%mod+mod)%mod;
        x+=x&-x;
    }
}
int get2(int x)
{
    int ret = 0;
    while(x)
    {
        ret = (ret+rs2[x])%mod;
        x-=x&-x;
    }
    return ret;
}

int SUM;

void Change(int u,int d)
{
    SUM=(SUM+d)%mod;
    while( u != -1 )
    {
        int f1 = top[u] , f = fa[f1];
        int lastsum=get(p[f1]),sum;
//      printf("u %d f1 %d d %d\n",u,f1,d);
        upp(p[f1],d);
        upp(p[u]+1,-d);
        if( f != -1 )
        {
            sum = get(p[f1]);
            int t = (ll)sum*sum%mod-(ll)lastsum*lastsum%mod;
            t = (t%mod+mod)%mod;
            upp2(p[f],t);
        }
        u = f;
    }
}

int Query(int u,int v){
    int f1 = top[u] , f2 = top[v];
    int ret = 0;
    while(f1^f2)
    {
        if( dep[f1] < dep[f2] )
        {
            swap(f1,f2);
            swap(u,v);
        }
        ret = ((ret+get2(p[u])-get2(p[f1]-1))%mod+mod)%mod;
        int t = get(p[f1]);
        ret = ((ret-(ll)t*t%mod)%mod+mod)%mod;
        if( son[u] != -1 ){
            int t = get(p[son[u]]);
            ret = ((ret+(ll)t*t%mod)%mod+mod)%mod;
        }
        u = fa[f1];
        f1 = top[u];
    }
    if( dep[u] > dep[v] ) swap(u,v);
    ret = ((ret+get2(p[v])-get2(p[u]-1))%mod+mod)%mod;
    if( son[v] != -1 ){
        int t = get(p[son[v]]);
        ret = ((ret+(ll)t*t%mod)%mod+mod)%mod;
    }
    int t = SUM - get(p[u]);
    ret = (ret+(ll)t*t%mod)%mod;
    ret = ( (ll)SUM*SUM%mod - ret ) % mod;
    return (ret+mod)%mod;
}

void init()
{
    clr(h,-1);
    si=0;
    pos=1;
}

int w[maxn];

int main()
{
    //freopen("input.txt","r",stdin);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        int u,v;
        for(int i=0;i1;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs1(1,-1,1);
        dfs2(1,1);
        clr(rs,0);
        clr(rs2,0);
        SUM=0;
        for(int i=1;i<=n;i++)
            Change(i,w[i]);
        /*for(int i=1;i<=n;i++)
            printf("i %d sum %d\n",i,get(p[i]));*/
        int a,b,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if( a == 1 )
            {
                Change(b,(c-w[b]+mod)%mod);
                w[b] = c;
            }else
                printf("%d\n",Query(b,c));
        }
    }
    return 0;
}

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