CodeForces 293E Close Vertices(点分治+Two Point法+树状数组)

来源:互联网 发布:安卓 知乎 输入法 编辑:程序博客网 时间:2024/05/18 02:58

关键词:点分治;Two Point法;树状数组
题意:给一棵含边权的树,求边条数不大于L,而且边权和不大于W的路径总数
解法:点分治;Two Point法;树状数组
点分治划归为以下问题:已知以重心为端点的所有<边条数,边长度>路径,求任意两条路径之和满足条件的对数。
首先,将得到的边按边权排序,再按边条数排序。
计算一边为第i条边的满足题意的对数:从后往前扫,扫到j满足a[i].length+a[j].length<=W,则j之前的所有路径都满足该条件。然后统计前j条边中与i的depth之和<=L的条数。这个可以用树状数组来完成:先统计所有边的depth,放入树状数组,每次j向前移动,即把j的depth移出树状数组。j停止移动时,树状数组中小于L-depth[i]的边条数即为所求。

#pragma comment(linker, "/STACK:102400000,102400000")#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#include <map>#define ll long long#define lowbit(x) x&(-x)#define INF 0x3f3f3f3fusing namespace std;const int maxn =100000+10;int n,L,W;struct Node{    int to,w;};vector<Node> g[maxn];int core,sum,son[maxn],maxs[maxn];struct node{    int depth,length;    bool operator<(const node &rhs)const {        return (length==rhs.length)?(depth<rhs.depth):(length<rhs.length);    }};vector<node> a[maxn],m;int cnt;ll ans;bool vis[maxn];void getcore(int u,int fa){    son[u]=1,maxs[u]=0;    for(int i=0;i<g[u].size();i++){        int v=g[u][i].to;        if(v==fa||vis[v]) continue;        getcore(v,u);        son[u]+=son[v]; maxs[u]=max(maxs[u],son[v]);    }    maxs[u]=max(maxs[u],sum-son[u]);    if(maxs[u]<maxs[core]) core=u;}void dfs(int u,int fa,int depth,int length){    a[cnt].push_back({depth,length});    son[u]=1;    m.push_back({depth,length});    for(int i=0;i<g[u].size();i++){        int v=g[u][i].to,w=g[u][i].w;        if(vis[v]||v==fa) continue;        dfs(v,u,depth+1,length+w);        son[u]+=son[v];    }}int s[maxn];void add(int l,int x,int maxx){    for(int i=l;i<=maxx;i+=lowbit(i))  s[i]+=x;}int ask(int x){    int ret=0;    for(int i=x;i>0;i-=lowbit(i)) ret+=s[i];    return ret;}ll cal(vector<node> &a){    ll ret=0;    int maxx=0;    for(int i=0;i<a.size();i++)  maxx=max(maxx,a[i].depth);    for(int i=1;i<=maxx;i++) s[i]=0;    for(int i=0;i<a.size();i++) add(a[i].depth,1,maxx);    for(int i=0,j=a.size()-1;i<a.size();i++){        while(i<j&&a[i].length+a[j].length>W) { add(a[j].depth,-1,maxx); j--; }        if(i>=j) break;        add(a[i].depth,-1,maxx);        ret+=ask(min(maxx,L-a[i].depth));    }    return ret;}void work(int u){    vis[u]=1,cnt=0;    if(sum==1) return;    for(int i=0;i<g[u].size();i++){        int v=g[u][i].to,w=g[u][i].w;        if(vis[v]) continue;        dfs(v,u,1,w);        sort(a[cnt].begin(),a[cnt].end());        cnt++;    }    sort(m.begin(),m.end());    ans+=cal(m);    for(int i=0;i<cnt;i++){        for(int j=0;j<a[i].size();j++)            if(a[i][j].length<=W&&a[i][j].depth<=L) ans++;        ans-=cal(a[i]);    }    m.clear();    for(int i=0;i<cnt;i++) a[i].clear();    for(int i=0;i<g[u].size();i++){        int v=g[u][i].to;        if(vis[v]) continue;        core=0; sum=son[v];        getcore(v,u);        work(core);    }}int main(){    //freopen("a.txt","r",stdin);    scanf("%d%d%d",&n,&L,&W);    for(int i=1;i<=n;i++) g[i].clear();    for(int i=2;i<=n;i++){        int u,w; scanf("%d%d",&u,&w);        g[i].push_back({u,w}),g[u].push_back({i,w});    }    memset(vis,0,sizeof(vis));    for(int i=0;i<=n;i++) a[i].clear();    m.clear();    ans=0;    core=0,sum=n,maxs[core]=INF;    getcore(1,0);    work(core);    printf("%I64d\n",ans);    return 0;}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 无锡天一初中考不进天一高中怎么办 校考一个都没过怎么办 拼音会拼不会写怎么办 20岁出头很迷茫怎么办 出了社会很迷茫怎么办 2018年现在会计工作难找怎么办 开广告店没生意怎么办 淘宝没有7天退怎么办 吃了松香的鸭子怎么办 理科生考电影专业研究生怎么办 pr导出视频很慢怎么办 8岁儿童头发稀少怎么办 八岁儿童版头发怎么办 小孩子有一块不长头发怎么办 小孩子头发上长癣怎么办 一岁多头发少怎么办 孩子头发长得慢怎么办 小孩头发长得慢怎么办 头发出油不洗头怎么办 青少年掉头发很厉害怎么办 洗了冷水头头痛怎么办 头发烫染后干枯毛躁怎么办 扎不起来的短发怎么办 发际线掉头发怎么办偏方 头上脓包掉头发怎么办 小孩头发少又黄怎么办 发旋哪里头发少怎么办 每次洗头发都掉好多怎么办 10岁儿童掉头发怎么办 1岁半宝宝掉头发怎么办 头发掉发严重怎么办吃什么 掉了一块钱很气怎么办 头发软又少怎么办盘头 头发出油掉的厉害怎么办 头发很油又少怎么办 18岁头发发量少怎么办 头发少长的慢怎么办 额头大发际线高怎么办 前额两边的头发变少了怎么办 吃减肥药掉头发怎么办 牙长智齿吃饭疼怎么办