2017 暑假艾教集訓 day8 (樹鏈剖分+樹上點分治)


POJ 2763

樹鏈剖分 邊權化點權問題(只需要把邊的權值給深度大的節點轉換爲點權值問題即可)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=100100;
int n,m,s;
struct node
{
    int to,next;
}edge[maxn*3];
int u[maxn],v[maxn],w[maxn],head[maxn],cnt=0;
void add(int u,int v)
{
    edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++;
}

int siz[maxn] , son[maxn] , fa[maxn] , deep[maxn] ;
int tid[maxn] , top[maxn] ,tot=0;
void dfs1(int u,int d,int pre)
{
    siz[u]=1;
    fa[u]=pre;
    deep[u] =  d;
    for(int i=head[u] ; i!=-1 ;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre)
        {
            dfs1(v,d+1,u);
            siz[u]+=siz[v];
            if(son[u]==-1 || siz[v]>siz[son[u]])
            {
                son[u]=v;
            }
        }
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;
    tid[u]=++tot;
    if(son[u]==-1) return;
    dfs2(son[u],tp);
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=son[u] && v!=fa[u])
        {
            dfs2(v,v);
        }
    }
}
#define lson rt<<1,begin,mid
#define rson rt<<1|1,mid+1,end
int tree[maxn<<2];
void pushup(int rt)
{
    tree[rt] = tree[rt<<1] + tree[rt<<1|1];
}
void updata(int rt,int begin,int end ,int pos,int val)
{
    if(begin==end)
    {
        tree[rt] = val; return;
    }
    int mid=(begin + end)>>1;
    if(mid>=pos) updata(lson,pos,val);
    else updata(rson,pos,val);
    pushup(rt);
}
int query(int rt,int begin,int end,int l,int r)
{
    if(begin >=l && r>=end)
    {
        return tree[rt];
    }
    int mid=(begin+end)>>1 ;
    int ans=0;
    if(mid >= l) ans+=query(lson,l,r);
    if(r > mid) ans+=query(rson ,l,r);
    return ans;
}
int getsum(int u,int v)
{
    int ans=0;
    while(top[u] != top[v])
    {
        if(deep[top[u]] < deep[top[v]]) swap(u,v);
        ans += query(1,1,n,tid[top[u]],tid[u]);
        u = fa[top[u]];
    }
    if(u==v) return ans;
    if(deep[u] > deep[v]) swap(u,v);
    return ans+query(1,1,n,tid[son[u]],tid[v]) ; // 爲啥!!!
}
int main()
{
    while(scanf("%d%d%d",&n,&m,&s)!=EOF)
    {
        memset(head,-1,sizeof(head)); cnt=0;
        memset(son,-1,sizeof(son));  tot=0;
        for(int i=0;i<n-1;++i)
        {
            scanf("%d%d%d",&u[i],&v[i],&w[i]);
            add(u[i],v[i]); add(v[i],u[i]);
        }
        dfs1(1,0,0);
        dfs2(1,1);
        memset(tree,0,sizeof(tree));
        for(int i=0;i<n-1;++i)
        {
            if(deep[u[i]]<deep[v[i]]) swap(u[i],v[i]);
            updata(1,1,n,tid[u[i]],w[i]);
        }
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==0)
            {
                int x;
                scanf("%d",&x);
                printf("%d\n",getsum(s,x));
                s=x;
            }
            else if(op==1)
            {
                int i,val;
                scanf("%d%d",&i,&val);
                updata(1,1,n,tid[u[i-1]],val);
            }
        }
    }
    return 0;
}


POJ 1741

樹上點分治第一題,還是沒太懂,先存下來以後慢慢研究

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=11111;
struct node
{
    int to,next,w;
}edge[maxn*5];
int head[maxn] , cnt=0;


void add(int u,int v,int w)
{
    edge[cnt].to=v;  edge[cnt].w=w;
    edge[cnt].next=head[u];  head[u] = cnt++;
}
int siz[maxn] , mx[maxn] ,deep[maxn] ,vis[maxn];
int dis[maxn] , num , mi, root ,ans , n, k;
void dfssize(int u,int pre)
{
    siz[u]=1;
    mx[u]=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre && !vis[v])
        {
            dfssize(v,u);
            siz[u] +=siz[v];
            if(siz[v]>mx[u]) mx[u]=siz[v];
        }
    }
}
void dfsroot(int r,int u,int fa)
{
    if(siz[r] - siz[u] > mx[u]) mx[u] = siz[r] -siz[u];
    if(mx[u] < mi) mi=mx[u] , root=u;
    for(int i=head[u];i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=fa && !vis[v]) dfsroot(r,v,u);
    }
}

void dfsdis(int u,int step,int pre)
{
    dis[num++]=step;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=pre &&!vis[v]) dfsdis(v,step+edge[i].w,u);
    }
}

int work(int u,int step)
{
    int ret=0;
    num=0;
    dfsdis(u,step,0);
    sort(dis,dis+num);
    int i=0 , j=num-1;
    while(i<j)
    {
        while(dis[i] + dis[j] > k && i < j ) j--;
        ret += (j-i);   i++;
    }
    return ret;
}
int dfs(int u)
{
    mi=n;
    dfssize(u,0);
    dfsroot(u,u,0);
    ans += work(root,0);
    vis[root] = 1;
    for(int i=head[root];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            ans-=work(v,edge[i].w);
            dfs(v);
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(!n && !k)break;
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
        cnt=0; ans=0;

        int u,v,w;
        for(int i=0;i<n-1;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w); add(v,u,w);
        }
        dfs(1);
        printf("%d\n",ans);
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章