bzoj 4372 烁烁的游戏 - 点分治 - 线段树

17人阅读 评论(0) 收藏 举报
分类:

动态点分治裸题

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
#define N 100010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
struct edges{
    int to,pre;
}e[N<<1];int h[N],etop,List[N],Lcnt;
inline int add_edge(int u,int v)
{
    return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
struct segment{
    int l,r,pt;
    segment *ch[2];
}*rt[N];int sz[N],d[N],pre[N];
map<int,int> zid[N],len[N],dz[N];
map<int,segment*> rtz[N];bool vis[N];
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r,rt->pt=0;
    int mid=(l+r)>>1;if(l==r) return 0;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
int update(segment* &rt,int s,int t,int v)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return rt->pt+=v;
    if(s<=mid) update(rt->ch[0],s,t,v);
    if(mid<t) update(rt->ch[1],s,t,v);
    return 0;
}
int query(segment* &rt,int p)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(l==r) return rt->pt;int ans=rt->pt;
    if(p<=mid) return ans+query(rt->ch[0],p);
    else return ans+query(rt->ch[1],p);
}
int getsz(int x,int fa)
{
    sz[x]=1;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to]&&e[i].to!=fa)
            sz[x]+=getsz(y,x);
    return sz[List[++Lcnt]=x];
}
int getrt(int &x)
{
    for(int i=1,fsz=sz[x],t=fsz;i<=Lcnt;i++)
    {
        int y=List[i],ysz=fsz-sz[y];
        for(int j=h[y];j;j=e[j].pre)
            if(sz[e[j].to]<sz[y]) ysz=max(ysz,sz[e[j].to]);
        if(ysz<t) t=ysz,x=y;
    }
    return Lcnt=0;
}
int solve(int x,int fa,int y,int z,int dis)
{
    len[x][y]=dis,d[y]=max(d[y],dis),
    zid[x][y]=z,dz[y][z]=max(dz[y][z],dis);
    for(int i=h[x],t;i;i=e[i].pre)
        if(!vis[t=e[i].to]&&e[i].to!=fa)
            solve(t,x,y,z,dis+1);
    return 0;
}
int dfs(int x,int las)
{
    getsz(x,0),getrt(x),pre[x]=las,vis[x]=true;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to])
            solve(y,x,x,y,1),build(rtz[x][y],0,dz[x][y]);
    build(rt[x],0,d[x]);
    for(int i=h[x],y;i;i=e[i].pre)
        if(!vis[y=e[i].to]) dfs(y,x);
    return 0;
}
inline int update(int x,int dis,int w)
{
    update(rt[x],0,min(d[x],dis),w);
    for(int y=pre[x];y;y=pre[y])
    {
        int z=zid[x][y],l=len[x][y];
        if(l>dis) continue;
        update(rt[y],0,min(dis-l,d[y]),w),
        update(rtz[y][z],0,min(dis-l,dz[y][z]),w);
    }
    return 0;
}
inline int query(int x)
{
    int ans=query(rt[x],0);
    for(int y=pre[x];y;y=pre[y])
    {
        int z=zid[x][y],l=len[x][y];
        ans+=query(rt[y],l)-query(rtz[y][z],l);
    }
    return ans;
}
char opt[10];
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        add_edge(u,v),add_edge(v,u);
    }
    dfs(1,0);
    while(m--)
    {
        scanf("%s",opt);int x,l,w;
        if(opt[0]=='Q') scanf("%d",&x),printf("%d\n",query(x));
        else scanf("%d%d%d",&x,&l,&w),update(x,l,w);
    }
    return 0;
}

查看评论

bzoj 4372: 烁烁的游戏 (动态点分治+线段树+LCA)

题目描述传送门题目大意:给一颗n个节点的树,边权均为1,初始点权均为0,m次操作: Q x:询问x的点权。 M x d w:将树上与节点x距离不超过d的节点的点权均加上w题解对于每个点开一棵线段树...
  • clover_hxy
  • clover_hxy
  • 2017-06-05 10:07:14
  • 440

[BZOJ4372][动态树分治(点分树)][动态开点线段树]烁烁的游戏

题意给一颗n个节点的树,边权均为1,初始点权均为0,m次操作: Q x:询问x的点权 M x d w:将树上与节点x距离不超过d的节点的点权均加上wdfs出点分树每个重心要记录这个重心以下的子点分...
  • Coldef
  • Coldef
  • 2017-02-28 18:23:19
  • 374

【BZOJ4372】烁烁的游戏 动态树分治

讲道理我第一次看到动态树分治以为和那个动态树LCT有关QAQ 然而正确的读法是【动态(树分治)】 这就很尴尬了。 题目大意就是给定一棵树,每个点初始权值是0,维护两个操作,一是将和某一个点距离不...
  • qq_34637390
  • qq_34637390
  • 2016-05-12 23:46:14
  • 800

【bzoj4372】 烁烁的游戏【动态树分治】

烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。 烁烁他每次会跳到一个节点u,把周围与他距...
  • ez_2016gdgzoi471
  • ez_2016gdgzoi471
  • 2017-12-20 13:56:44
  • 325

[点分树] BZOJ 4372: 烁烁的游戏

DescriptionDescription给定一颗nn个节点的树,边权均为11,初始树上没有皮皮鼠。 烁烁他每次会跳到一个节点uu,把周围与他距离不超过dd的节点各吸引出ww只皮皮鼠。皮皮鼠会被烁...
  • Vectorxj
  • Vectorxj
  • 2017-12-07 12:39:37
  • 775

bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆

bzoj2006: 定义一个四元组{x,l,r,w},表示左端点在x,右端点在[l,r]的超级和弦的最大美妙度在将w作为右端点时取到,w可以用前缀和+线段树/ST表求出。 对于每个i,我们将{i,i+...
  • gjghfd
  • gjghfd
  • 2017-05-26 16:42:32
  • 177

[线性基 树链剖分 线段树 || ST表 || 点分治] BZOJ 4568 [Scoi2016]幸运数字

这个东西链剖之后就是个裸的区间线性基,是可以暴力合并的O(log2n)O(\log ^2 n) 所以暴力线段树是 O(nlog4n)O(n\log ^4n) 改成ST表是 O(nlog3n)O(n...
  • u014609452
  • u014609452
  • 2017-07-01 22:06:10
  • 326

bzoj 3672 [Noi2014]购票 (线段树+凸壳)

#include #include #include #include #include #include using namespace std; #define N 200020 ...
  • u013654696
  • u013654696
  • 2016-07-24 16:54:06
  • 223

分治技巧在高级数据结构中的应用——线段树分治(二)&&bzoj4137火星商店问题详解

分治技巧在高级数据结构中的应用——线段树分治(二) 从一道神题说起 4137: [FJOI2015]火星商店问题 Time Limit: 20 Sec  Memory Limit: 25...
  • lvzelong2014
  • lvzelong2014
  • 2017-12-01 17:11:20
  • 360

[二进制分组 线段树 || 点分治 分治] UOJ #191 【集训队互测2016】Unknown

详见lzz的集训队论文二进制分组做法二进制分组是在线段树的结构上做的 方便区间查询 至于删除 采用延迟重构的思想 每一层只有最后一个区间是萎的 我们需要递归下去 询问还是O(logn)O(\log ...
  • u014609452
  • u014609452
  • 2017-05-28 11:15:45
  • 609
    个人资料
    持之以恒
    等级:
    访问量: 3万+
    积分: 2120
    排名: 2万+
    最新评论