临阵磨枪

马上区域赛了 ,每天刷一些自己以前写过的题,记录在博客里督促自己,

点分治:poj1741,求树上长度在kr区间内的路径个数

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1e4+4,inf = 0x3f3f3f3f;
#define ll long long
struct Node{int to,nex,w;}e[M<<1];
int n,k,head[M<<1],cnt,mx,vis[M],rt,sum,siz[M];
ll rhs=0,d[M<<1];

void getrt(int x,int f,int mm=0){
    siz[x]=1;
    for(int to,i=head[x];~i;i=e[i].nex){
        to=e[i].to;
        if(vis[to]||to==f)continue;
        getrt(to,x);
        siz[x]+=siz[to];
        if(mm<siz[to])mm=siz[to];
    }
    if(mm<sum-siz[x])mm=sum-siz[x];
    if(mx>mm)mx=mm,rt=x;
}

void dfs(int x,int f){
    siz[x]=1;
    for(int to,i=head[x];~i;i=e[i].nex){
        to=e[i].to;
        if(vis[to]||to==f)continue;
        dfs(to,x);
        siz[x]+=siz[to];
    }
}
void getdis(int x,int f,ll dis){
//    cout<<x<<endl;
    d[++d[0]]=dis;
    for(int to,i=head[x];~i;i=e[i].nex){
        to=e[i].to;
        if(vis[to]||to==f)continue;
        getdis(to,x,dis+e[i].w);
    }
}
ll calc(int x,int f,ll dis){
    ll ans=0;d[0]=0;
    getdis(x,f,dis);
//    cout<<d[0]<<endl;
    sort(d+1,d+d[0]+1);
    int l=1,r=d[0];
    while(l<r){
        if(d[l]+d[r]<=k)ans+=r-l,l++;
        else r--;
    }
    return ans;
}
void slove(int x){
    rhs += calc(x,0,0);
    vis[x]=1;
//    cout<<x<<":"<<rhs<<endl;
    for(int to,i=head[x];~i;i=e[i].nex){
        to=e[i].to;
        if(vis[to])continue;
        rhs-=calc(to,x,e[i].w);//容斥原理
        mx=inf;
        sum=siz[to];
        getrt(to,0);
        dfs(rt,0);
        slove(rt);
    }
}

int main(){
    while(~scanf("%d%d",&n,&k)){
        if(n==0&&k==0)return 0;
        memset(head,-1,sizeof(head));  cnt=1;
        memset(vis,0,sizeof(vis));         rhs=0;

        for(int x,y,w,i=1;i<n;i++){
            scanf("%d%d%d",&x,&y,&w);
            e[cnt].to=y; e[cnt].w=w; e[cnt].nex=head[x]; head[x]=cnt++;
            e[cnt].to=x; e[cnt].w=w; e[cnt].nex=head[y]; head[y]=cnt++;
        }

        mx=inf;
        sum=n;
        getrt(1,0);
        dfs(rt,0);

        slove(rt);

        printf("%lld\n",rhs);

    }
    return 0;
}

10.15  21:32 长链剖分:洛谷3899

题目描述

设 T 为一棵有根树,我们做如下的定义:

• 设 a 和 b 为 T 中的两个不同节点。如果 a 是 b 的祖先,那么称“a 比 b 不知道高明到哪里去了”。

• 设 a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称“a 与 b 谈笑风生”。

给定一棵 n 个节点的有根树 T,节点的编号为 1 ∼ n,根节点为 1 号节点。你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多少个有序三元组 (a; b; c) 满足:

  1. a、 b 和 c 为 T 中三个不同的点,且 a 为 p 号节点;

  2. a 和 b 都比 c 不知道高明到哪里去了;

  3. a 和 b 谈笑风生。这里谈笑风生中的常数为给定的 

    #include<bits/stdc++.h>
    using namespace std;
    using  ll = long long ;
    constexpr int M=3e5+5;
    struct Node{int to,nex;}e[M<<1];
    struct node{int k,id;};
    int n,m,cnt,dis[M],siz[M],len[M],son[M],head[M<<1];
    ll ans[M],tmp[M],*id=tmp,*f[M];
    vector<node> q[M];
    void dfs1(int x,int f){
        siz[x]=1;
        for(int to,i=head[x];~i;i=e[i].nex){
            to=e[i].to;
            if(to==f)continue;
            dis[to]=dis[x]+1;
            dfs1(to,x);
            siz[x]+=siz[to];
            if(len[son[x]]<len[to])son[x]=to;
        }
        len[x]=len[son[x]]+1;
    }
    void dfs2(int x,int fa){
        if(son[x]) f[son[x]]=f[x]+1,dfs2(son[x],x);
    
        for(int to,i=head[x];~i;i=e[i].nex){
            to=e[i].to;
            if(to==fa||to==son[x])continue;
            f[to]=id;id+=len[to];
            dfs2(to,x);
            for(int j=0;j<len[to];j++)f[x][j+1]+=f[to][j];
        }
    
    
        for(int k,id,i=0;i<q[x].size();i++){
            k=q[x][i].k;
            id=q[x][i].id;
            ans[id]=(ll)(siz[x]-1)*min(k,dis[x]);
            if(len[x]<=k+1)ans[id]+=f[x][1];
            else ans[id]+=f[x][1]-f[x][k+1];
        }
        f[x][0]=f[x][1]+siz[x]-1;
    }
    int main(){
        memset(head,-1,sizeof(head));cnt=1;
    
        scanf("%d%d",&n,&m);
        for(int x,y,i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            e[cnt].to=y; e[cnt].nex=head[x]; head[x]=cnt++;
            e[cnt].to=x; e[cnt].nex=head[y]; head[y]=cnt++;
        }
        for(int x,k,i=1;i<=m;i++){
            scanf("%d%d",&x,&k);
            q[x].push_back((node){k,i});
        }
        dfs1(1,0);
        f[1]=id;id+=len[1];
        dfs2(1,0);
        for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
        return 0;
    }
    

    树上主席树+树剖lca:洛谷2633

    #include<bits/stdc++.h>
    using namespace std;
    const int M=1e5+5;
    #define ll long long
    struct Edge{ll to,nex;}e[M<<1];
    struct Node{ll ls,rs,sum;}t[M*40];
    ll las,n,m,d[M],b[M],head[M<<1],cnt,rot[M];
    ll siz[M],son[M],fa[M],top[M],dep[M];
    
    
    void dfs1(ll x,ll f){
        siz[x]=1;
        fa[x]=f;
        for(ll to,i=head[x];~i;i=e[i].nex){
            to=e[i].to;
            if(to==f)continue;
            dfs1(to,x);
            siz[x]+=siz[to];
            if(siz[son[x]]<siz[to])son[x]=to;
        }
    }
    void dfs2(ll x,ll tp){
        top[x]=tp;
        if(son[x])dfs2(son[x],tp);
        for(ll to,i=head[x];~i;i=e[i].nex){
            to=e[i].to;
            if(to!=son[x]&&to!=fa[x])dfs2(to,to);
        }
    }
    ll lca(ll x,ll y){
        while(top[x]!=top[y])
            if(dep[top[x]]<dep[top[y]]) y=fa[top[y]];
            else x=fa[top[x]];
        return dep[x]<dep[y]?x:y;
    }
    
    
    void build(ll &k,ll l,ll r){
        k=++cnt;
        t[k].sum=t[k].ls=t[k].rs=0;
        if(l==r)return ;
        ll mid=(l+r)>>1;
        build(t[k].ls,l,mid);   build(t[k].rs,mid+1,r);
    }
    void update(ll &k,ll pre,ll l,ll r,ll v){
        k=++cnt;   t[k]=t[pre];    t[k].sum++;
        if(l==r)return ;
        ll mid=(l+r)>>1;
        if(v<=mid) update(t[k].ls, t[pre].ls, l,mid, v);
        else update(t[k].rs, t[pre].rs, mid+1,r, v);
    }
    void dfs(ll x,ll f){
        dep[x]=dep[f]+1;
        update(rot[x],rot[f],1,b[0],d[x]);
    
        for(ll i=head[x];~i;i=e[i].nex)
            if(e[i].to!=f) dfs(e[i].to,x);
    }
    ll ask(ll k,ll pre,ll l,ll r,ll now,ll lcaa,ll flca){
        if(l==r)return l;
        ll mid=(l+r)>>1,num=t[ t[k].ls ].sum+t[ t[pre].ls ].sum - t[ t[lcaa].ls ].sum -t[ t[flca].ls ].sum;
        if(now<=num)return ask(t[k].ls,t[pre].ls,l,mid,now,t[lcaa].ls,t[flca].ls);
        return ask(t[k].rs,t[pre].rs,mid+1,r,now-num,t[lcaa].rs,t[flca].rs);
    }
    
    int main(){
        memset(head,-1,sizeof(head));
        cnt=1;
        scanf("%lld%lld",&n,&m);
        for(ll i=1;i<=n;i++)scanf("%lld",&d[i]),b[i]=d[i];
    
        sort(b+1,b+n+1);//手写unique离散化
        b[0]=1;for(ll i=2;i<=n;i++) if(b[i]!=b[i-1])b[++b[0]]=b[i];
        for(ll i=1;i<=n;i++) d[i]=lower_bound(b+1,b+b[0]+1,d[i])-b;
    
        for(ll x,y,i=1;i<n;i++){
            scanf("%lld%lld",&x,&y);
            e[cnt].to=y; e[cnt].nex=head[x]; head[x]=cnt++;//链式前向星建图
            e[cnt].to=x; e[cnt].nex=head[y]; head[y]=cnt++;
        }
    
    
        cnt=0;//树链剖分lca
        dfs1(1,0);
        dfs2(1,1);
    
        cnt=0;
        build(rot[0],1,b[0]);//树上主席树初始化
        dfs(1,0);
    
        for(ll u,v,k,i=1;i<=m;i++){
            scanf("%lld%lld%lld",&u,&v,&k);
            u^=las;
            if(dep[u]<dep[v])swap(u,v);
            las=ask(rot[u],rot[v],1,b[0],k,rot[lca(u,v)],rot[fa[lca(u,v)]]);
            las=b[las];
            printf("%lld\n",las);
        }
        return 0;
    }
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值