BZOJ 4012 HNOI2015 开店 动态树分治+二分

题目大意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和,强制在线

没记错的话这题我知道的有三种解法来着?

(茴香豆的茴有四种写法泥萌知道嘛…?

1.线段树维护虚树

2.点分治+线段树

3.分块

第一种方法我不知道在线怎么搞= = (我并不知道怎么在虚树上进行点定位

第三种方法貌似内存过不去?

于是果断点分治+线段树

写完发现内存还是炸了= = O(nlog2n)的内存说什么也过不去啊= =

后来发现既然维护的是和不是最值那还要线段树干嘛= =

直接开个vector维护前缀和直接二分不就好了= =

时间复杂度O(nlog2n)

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 150100
#define B 400
using namespace std;
typedef vector<pair<int,long long> > abcd;
int n,m,A;
int a[M];
long long last_ans;
namespace Tree{
    struct edge{
        int to,f,next;
        bool ban;
    }table[M<<1];
    int head[M],tot=1;
    int dpt[M],pos[M],T;
    int log_2[M<<1],min_dpt[M<<1][18];
    void Add(int x,int y,int z)
    {
        table[++tot].to=y;
        table[tot].f=z;
        table[tot].next=head[x];
        head[x]=tot;
    }
    void DFS(int x,int from)
    {
        int i;
        min_dpt[pos[x]=++T][0]=dpt[x];
        for(i=head[x];i;i=table[i].next)
            if(table[i].to!=from)
            {
                dpt[table[i].to]=dpt[x]+table[i].f;
                DFS(table[i].to,x);
                min_dpt[++T][0]=dpt[x];
            }
    }
    void Build_LCA()
    {
        int i,j;
        for(i=2;i<=T;i++)
            log_2[i]=log_2[i>>1]+1;
        for(j=1;j<=log_2[T];j++)
            for(i=1;i+(1<<j)-1<=T;i++)
                min_dpt[i][j]=min(min_dpt[i][j-1],min_dpt[i+(1<<j-1)][j-1]);
    }
    long long LCA_Depth(int x,int y)
    {
        x=pos[x];y=pos[y];
        if(x>y) swap(x,y);
        int l=log_2[y-x+1];
        return min(min_dpt[x][l],min_dpt[y-(1<<l)+1][l]);
    }
    long long Distance(int x,int y)
    {
        return dpt[x]+dpt[y]-2*LCA_Depth(x,y);
    }
}
pair<long long,int> operator + (const pair<long long,int> x,const pair<long long,int> y)
{
    return make_pair(x.first+y.first,x.second+y.second);
}
pair<long long,int> operator - (const pair<long long,int> x,const pair<long long,int> y)
{
    return make_pair(x.first-y.first,x.second-y.second);
}
/*
struct Segtree{
    Segtree *ls,*rs;
    long long sum1;
    int sum2;
    //sum1代表子树中所有点到该点的距离之和
    //sum2代表子树中点的个数
    void* operator new(size_t)
    {
        static Segtree *mempool,*C;
        if(C==mempool)
            mempool=(C=new Segtree[1<<15])+(1<<15);
        C->ls=C->rs=0x0;
        C->sum1=C->sum2=0;
        return C++;
    }
    friend void Insert(Segtree *&p,int x,int y,int pos,int val)
    {
        int mid=x+y>>1;
        if(!p) p=new Segtree;
        p->sum1+=val;
        p->sum2++;
        if(x==y) return ;
        if(pos<=mid)
            Insert(p->ls,x,mid,pos,val);
        else
            Insert(p->rs,mid+1,y,pos,val);
    }
    pair<long long,int> Query(Segtree *p,int x,int y,int l,int r)
    {
        int mid=x+y>>1;
        if(!p) return make_pair(0ll,0);
        if(x==l&&y==r)
            return make_pair(p->sum1,p->sum2);
        if(r<=mid)
            return Query(p->ls,x,mid,l,r);
        if(l>mid)
            return Query(p->rs,mid+1,y,l,r);
        return Query(p->ls,x,mid,l,mid) + Query(p->rs,mid+1,y,mid+1,r);
    }
};
*/
namespace Dynamic_TDC{
    using namespace Tree;
    abcd sum1[M],sum2[M];
    int fa[M];
    int Get_Size(int x,int from)
    {
        int i,re=1;
        for(i=head[x];i;i=table[i].next)
            if(!table[i].ban&&table[i].to!=from)
                re+=Get_Size(table[i].to,x);
        return re;
    }
    int Get_Centre_Of_Gravity(int x,int from,int size,int &cg)
    {
        int i,re=1,flag=true;
        for(i=head[x];i;i=table[i].next)
            if(!table[i].ban&&table[i].to!=from)
            {
                int temp=Get_Centre_Of_Gravity(table[i].to,x,size,cg);
                if(temp<<1>size)
                    flag=false;
                re+=temp;
            }
        if(size-re<<1>size)
            flag=false;
        if(flag) cg=x;
        return re;
    }
    void DFS(int x,int from,int dpt,abcd &sum1,abcd &sum2)
    {
        int i;
        sum1.push_back(pair<int,long long>(a[x],dpt));
        sum2.push_back(pair<int,long long>(a[x],dpt));
        for(i=head[x];i;i=table[i].next)
            if(!table[i].ban&&table[i].to!=from)
                DFS(table[i].to,x,dpt+table[i].f,sum1,sum2);
    }
    int Tree_Divide_And_Conquer(int x)
    {
        abcd::iterator it;
        int i,j,size=Get_Size(x,0);
        Get_Centre_Of_Gravity(x,0,size,x);
        sum1[x].push_back(pair<int,long long>(a[x],0));
        for(i=head[x];i;i=table[i].next)
            if(!table[i].ban)
            {
                table[i].ban=table[i^1].ban=true;
                abcd temp;
                DFS(table[i].to,0,table[i].f,temp,sum1[x]);
                int y=Tree_Divide_And_Conquer(table[i].to);
                sum2[y]=temp;fa[y]=x;
                sum2[y].push_back(pair<int,long long>(-1,0));
                sort(sum2[y].begin(),sum2[y].end());
                for(j=1;j<sum2[y].size();j++)
                    sum2[y][j].second+=sum2[y][j-1].second;
            }
        sum1[x].push_back(pair<int,long long>(-1,0));
        sort(sum1[x].begin(),sum1[x].end());
        for(j=1;j<sum1[x].size();j++)
            sum1[x][j].second+=sum1[x][j-1].second;
        return x;
    }
    pair<long long,int> Query(abcd &a,int l,int r)
    {
        if(a.empty())
            return pair<long long,int>(0,0);
        abcd::iterator it1=lower_bound(a.begin(),a.end(),pair<int,long long>(l,0));
        abcd::iterator it2=lower_bound(a.begin(),a.end(),pair<int,long long>(r+1,0));
        it1--;it2--;
        return make_pair(it2->second-it1->second,it2-it1);
    }
    long long Query(int x,int l,int r)
    {
        int i;
        long long re=Query(sum1[x],l,r).first;
        for(i=x;fa[i];i=fa[i])
        {
            pair<long long,int> temp=Query(sum1[fa[i]],l,r)-Query(sum2[i],l,r);
            re+=temp.first+temp.second*Distance(x,fa[i]);
        }
        return re;
    }
}
int main()
{
    using namespace Tree;
    using namespace Dynamic_TDC;
    int i,x,y,z;
    cin>>n>>m>>A;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        Add(x,y,z);Add(y,x,z);
    }
    DFS(1,0);Build_LCA();
    Tree_Divide_And_Conquer(1);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        y=(y+last_ans)%A;
        z=(z+last_ans)%A;
        if(y>z) swap(y,z);
        printf("%lld\n",last_ans=Query(x,y,z));
    }
    return 0;
}
时间: 2024-10-10 12:23:22

BZOJ 4012 HNOI2015 开店 动态树分治+二分的相关文章

【bzoj4012】[HNOI2015]开店 动态树分治+二分查找

题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这个树所有顶点的

[BZOJ 4012][HNOI2015]开店(树链剖分+主席树)

Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群.很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来.每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i.妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻.所以这

[BZOJ4012][HNOI2015]开店(动态点分治)

4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status][Discuss] Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面 向什么样的人群.很神奇的是,幻想乡的地

BZOJ 4012 HNOI2015 开店 树的边分治

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权值,现在有Q组询问,每组给出信息u,L,R,问点权在区间[L,R]的点到点u的距离和为多少.强制在线. N<=150000,Q<=200000. 可能这是我这几天做过的题里面最水但是最码的一个了.... 实际上看见树上所有点的度不超过3就感觉可以用边分治做,具体的思路实际上很简单,建立一个边分治结

BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆

题目大意:给定一棵树,一开始每个点都是黑点,多次改变某个点的状态或询问距离最远的两个黑点的距离 <珍爱生命远离STL可是我还是可耻地用了STL系列> 传说中的动态树分治...其实并没有那么神嘛= = ↑别听这傻瓜瞎说这货被STL卡了一天QAQ 我们把分治过程中遍历过的重心都连起来 上一层的重心链接下一层的重心 可以得到一棵新的树 下面我们开始讨论这棵新树 显然这棵树的高度不会超过O(logn) 然后我们每个节点开两个堆 第一个堆记录子树中所有节点到父亲节点的距离 第二个堆记录所有子节点的堆顶

BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治

题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和 此生无悔入东方,来世愿生幻想乡 首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改 用动态树分治就好了嘛... 每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本 然后一直向上扫到根就能统计了 ↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧 然后就好搞了... 对于分治结构的每一个点,我们枚举它的出边 如果某条出边连向的点的距离之和小于当前点,那么答案

【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态树分治

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,并

【BZOJ3730】震波 动态树分治+线段树

[BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动.接下来你需要在线处理M次操作:0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和.1 x y 表示第x个城市的价值变成了y.为了体现程序的在

动态树分治

感受: 就是把分治结构变成树(并不需要真正建出,只需要记录父亲) 然后每个点维护子树到该点的信息,和子树到父亲点的信息 总体来说还是很模板的一个东西 题目大概分成两类: (1)树上黑白点染色,问一个点到所有黑点的距离和 这种就是原来真正的树结构上信息修改,那么一般就是将修改的点在分治树上所在的链每个点维护的信息加加减减. (2)另一种就是询问体现动态,比如距离某个点距离<=k的点的权值和 这种问题的突破点在于原树的信息是不改变的.所以我们可以在分治树上每个点维护一个vector数组来储存信息(有