2017 暑假艾教集训 day8 (树链剖分+树上点分治)

来源:互联网 发布:沙宣男士洗发水 知乎 编辑:程序博客网 时间:2024/06/06 01:40


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,endint 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;}