【noip】2016 运输计划

可以使用树剖 nlog^2n 卡常后能过 就是码量有点大

详解在这里:https://www.luogu.org/blog/29354/solution-p2680

#include<bits/stdc++.h>
#define R register

using namespace std;
const int maxn=3e5+5;
char *P;
void QREAD()
{
    static char buf[1<<25];P=&buf[0];
    fread(buf,1,1<<25,stdin);
}

char get_char()
{
    return *(P++);
}

void readint(int &x)
{
    char ch=get_char();int f=1;x=0;
    for(;;)
    {
        if(ch=='-')f=-1;
        if(ch<'0'||ch>'9');
        else break;
        ch=get_char();
    }
    for(;;)
    {
        if(ch<'0'||ch>'9')break;
        x*=10;x+=ch-'0';
        ch=get_char();
    }x*=f;
}

struct rmq
{
    int t[maxn<<2],lazy[maxn<<2];
    void pushup(int x){t[x]=max(t[x<<1],t[x<<1|1]);}
    void pushdown(int x)
    {
        if(lazy[x]==0)return ;
        lazy[x<<1]=max(lazy[x<<1],lazy[x]);
        lazy[x<<1|1]=max(lazy[x<<1|1],lazy[x]);
        t[x<<1]=max(t[x<<1],lazy[x<<1]);
        t[x<<1|1]=max(t[x<<1|1],lazy[x<<1|1]);
    }
    void modify(int ql,int qr,int l,int r,int x,int val)
    {
        if(ql>qr)return;
        if(ql<=l&&r<=qr)
        {
            t[x]=max(t[x],val);lazy[x]=max(lazy[x],val);
            return ;
        }
        int m=(l+r)>>1;
        pushdown(x);
        if(ql<=m)modify(ql,qr,l,m,x<<1,val);
        if(m<qr)modify(ql,qr,m+1,r,x<<1|1,val);
        pushup(x);
    }
    int query(int ql,int qr,int l,int r,int x)
    {
        if(ql>qr)return -1;
        if(ql<=l&&r<=qr)return t[x];
        int m=(l+r)>>1,ret=-1;
        pushdown(x);
        if(ql<=m)ret=max(ret,query(ql,qr,l,m,x<<1));
        if(m<qr)ret=max(ret,query(ql,qr,m+1,r,x<<1|1));
        return ret;
    }
}T;

struct segtreesum
{
    int t[maxn<<2],lazy[maxn<<2];
    void pushup(int x){t[x]=t[x<<1]+t[x<<1|1];}
    void pushdown(int x,int ls,int rs)
    {
        if(lazy[x]==0)return ;
        t[x<<1]+=lazy[x]*ls;t[x<<1|1]+=lazy[x]*rs;
        lazy[x<<1]+=lazy[x];lazy[x<<1|1]+=lazy[x];
        lazy[x]=0;
    }
    void modify(int ql,int qr,int l,int r,int x,int val)
    {
        if(ql>qr)return;
        if(ql<=l&&r<=qr)
        {
            t[x]+=val;lazy[x]+=val;
            return ;
        }
        int m=(l+r)>>1;
        pushdown(x,m-l+1,r-m);
        if(ql<=m)modify(ql,qr,l,m,x<<1,val);
        if(m<qr)modify(ql,qr,m+1,r,x<<1|1,val);
        pushup(x);
    }
    int query(int ql,int qr,int l,int r,int x)
    {
        if(ql>qr)return 0;
        if(ql<=l&&r<=qr)return t[x];
        int m=(l+r)>>1,ret=0;
        pushdown(x,m-l+1,r-m);
        if(ql<=m)ret+=query(ql,qr,l,m,x<<1);
        if(m<qr)ret+=query(ql,qr,m+1,r,x<<1|1);
        return ret;
    }
}t;

struct Edge
{
    int to,val,nxt;
}edge[maxn<<2];int EC;
int head[maxn];
void add(int a,int b,int t)
{
    ++EC;
    edge[EC].nxt=head[a];edge[EC].to=b;edge[EC].val=t;head[a]=EC;
}

int n,m;
void read()
{
    readint(n);readint(m);
    for(R int i=1; i<n; i++)
    {
        R int a,b,t;
        readint(a);readint(b);readint(t);
        add(a,b,t);
        add(b,a,t);
    }
}

int mson[maxn],dep[maxn],sz[maxn],fa[maxn];
void dfs1(int x,int f)
{
    dep[x]=dep[f]+1;sz[x]=1;fa[x]=f;
    for(R int i=head[x];i!=0; i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==f)continue;
        dfs1(to,x);
        if(mson[x]==0)mson[x]=to;else if(sz[mson[x]]<sz[to])mson[x]=to;
        sz[x]+=sz[to];
    }
}
int id[maxn],cnt=0,top[maxn];
void dfs2(int x,int tp)
{
    ++cnt;id[x]=cnt;top[x]=tp;
    if(!mson[x])return ;
    dfs2(mson[x],tp);
    for(R int i=head[x]; i!=0; i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fa[x]||to==mson[x])continue;
        dfs2(to,to);
    }
}

int elen[maxn];
void count(int x,int tl)
{
    //和普通点权不同的是,对于一颗树来说,每一个点的点权被定义为他的父亲到他的边权
    //边转点 
    elen[id[x]]=tl;
    if(x!=1)
    {
        t.modify(id[x],id[x],1,n,1,tl);
    }
    for(R int i=head[x];i!=0;i=edge[i].nxt)
    {
        int to=edge[i].to,val=edge[i].val;
        if(to==fa[x])continue;
        count(to,val);
    }
}

int ask(int u,int v)
{
    R int ret=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]])swap(u,v);
        ret+=t.query(id[top[v]],id[v],1,n,1);
        v=fa[top[v]];
    }
    if(dep[u]>dep[v])swap(u,v);
    ret+=t.query(id[u]+1,id[v],1,n,1);
    return ret;
}

int ans,ori;

void go(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]])swap(u,v);
        ans=min(ans,max(ori-elen[id[v]],T.query(id[v],id[v],1,n,1)));
        v=fa[v];
    }
    if(dep[u]>dep[v])swap(u,v);
    while(u!=v)
    {
        ans=min(ans,max(ori-elen[id[v]],T.query(id[v],id[v],1,n,1)));
        v=fa[v];
    }
}

vector<pair<int,int> >chain[maxn];int csz;

void makechain(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]])swap(u,v);
        int st=id[top[v]],ed=id[v];
        if(st<=ed)chain[csz].push_back(make_pair(st,ed));
        v=fa[top[v]];
    }
    if(dep[u]>dep[v])swap(u,v);
    int st=id[u]+1,ed=id[v];if(st<=ed)chain[csz].push_back(make_pair(st,ed));
    csz++;
}

vector<pair<int,int> >query;
vector<int>qans;
int mem;

void prepare()
{
    dfs1(1,1);
    dfs2(1,1);
    count(1,1);
}
void solve()
{
    prepare();
    ans=-1;
    for(R int i=1;i<=m;i++)
    {
        R int u,v;readint(u);readint(v);
        query.push_back(make_pair(u,v));
        makechain(u,v);
        int len=ask(u,v);qans.push_back(len);
        if(len>ans)ans=len,mem=i-1;
    }
    ori=ans;
    for(R int i=0;i<csz;i++)
    {
        sort(chain[i].begin(),chain[i].end());
        int st=1;
        for(int j=0;j<(int)chain[i].size();j++)
        {
            T.modify(st,chain[i][j].first-1,1,n,1,qans[i]);
            st=chain[i][j].second+1;
        }
        T.modify(st,n,1,n,1,qans[i]);
    }
    go(query[mem].first,query[mem].second);
    printf("%d\n",ans);
}

int main()
{
    QREAD();
    read();
    solve();
    return 0;
}

或者使用树上差分

check函数:check(t)

      设路径长度超过t的路径的总数为s,如果一条边被经过恰好s次,且maxlen(最长路径长度)-edgelen<=t 那么就可行

(卡常好烦)

#include<bits/stdc++.h>
#define R register
using namespace std;

const int maxn=3e5+5;

char *P;
void qread(){static char buf[1<<24];fread(buf,1,1<<24,stdin);P=&buf[0];}
char get_char(){return *P++;}
void readint(int &x)
{
    int f=1;x=0;char ch;
    for(;;)
    {
        ch=getchar();
        if(ch=='-'){f=-1;ch=getchar();break;}
        if(ch<'0'||ch>'9');else break;
    }
    for(;;)
    {
        if(ch<'0'||ch>'9')break;
        x*=10;x+=ch-'0';ch=getchar();
    }
    x*=f;
}

int n,m;
struct EDGE
{
	int to,val,nxt;
}edge[maxn<<3];int ec;
int head[maxn];
void addedge(int u,int v,int l)
{
	++ec;
	edge[ec].nxt=head[u];edge[ec].val=l;edge[ec].to=v;
	head[u]=ec;
}
//--------------------lca
int fa[maxn];
int Log[maxn<<3];
int st[21][maxn<<3];
int ord[maxn<<2],ptr,in[maxn],dep[maxn];
void dfs(int x,int f)
{
    ++ptr;ord[ptr]=x;in[x]=ptr;
    fa[x]=f;dep[x]=dep[f]+1;
    for(R int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==f)continue;
        dfs(to,x);
        ++ptr;ord[ptr]=x;
    }
}
int query(int x,int y)
{
    int l=min(x,y),r=max(x,y);
    int len=r-l+1,lg=Log[len];
    int a=st[lg][l],b=st[lg][r-(1<<lg)+1];
    return dep[a]<dep[b]?a:b;
}
int Lca(int u,int v)
{
    return query(in[u],in[v]);
}
void bld()
{
    for(int i=1;i<=ptr;i++)
    {
        st[0][i]=ord[i];
    }
    for(R int j=1;j<=19;j++)
    {
        for(R int i=1;i+(1<<j)<=ptr;i++)
        {
            int a=st[j-1][i],b=st[j-1][i+(1<<(j-1))];
            st[j][i]=dep[a]<dep[b]?a:b;
        }
    }
}
//---------------------------------------------
int elen[maxn],dis[maxn];
void getlen(int x,int el)
{
    elen[x]=el;
    for(R int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to,len=edge[i].val;
        if(to==fa[x])continue;
        dis[to]=dis[x]+len;getlen(to,len);
    }
}
int len[maxn],mxl,mxe;
int q1[maxn],q2[maxn],lca[maxn];
void prepare()
{
    for(R int i=1;i<=m;i++)
    {
        len[i]=-2*dis[lca[i]]+dis[q1[i]]+dis[q2[i]];
        mxl=max(mxl,len[i]);
    }
}
int ROOT;
int buc[maxn],cnt[maxn];
void sum(int x)
{
    cnt[x]=buc[x];
    for(R int i=head[x];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(to==fa[x])continue;
        sum(to);
        cnt[x]+=cnt[to];
    }
}
int check(int t)
{
    memset(buc,0,sizeof(buc));
    int mxlen=-1;
    int cc=0;
    for(R int i=1;i<=m;i++)
    {
        if(len[i]>t)
        {
            buc[q1[i]]++;buc[q2[i]]++;buc[lca[i]]-=2;
            mxlen=max(mxlen,len[i]);
            cc++;
        }
    }
    sum(ROOT);
    int f=0;
    for(R int i=1;i<=n;i++)
    {
        if(cnt[i]==cc)
        {
            if(mxlen-elen[i]<=t)
            {
                f=1;break;
            }
        }
    }
    return f;
}

void solve()
{
    int l=mxl-mxe,r=mxl,ans=0;
    while(l<=r)
    {
        int m=l+r>>1;
        if(check(m))
        {
            ans=m;r=m-1;
        }
        else l=m+1;
    }
    printf("%d\n",ans);
}

int main()
{
//	freopen("transport.in","r",stdin);freopen("transport.out","w",stdout);
	srand(time(0));
    readint(n);readint(m);
    ROOT=rand()%n+1;
    for(int i=1;i<n;i++)
    {
        int a,b,t;readint(a);readint(b);readint(t);
        addedge(a,b,t);
        addedge(b,a,t);
        mxe=max(mxe,t);
    }
    
    dfs(ROOT,ROOT);getlen(ROOT,0);bld();
    for(int i=0;i<=20;i++)
    {
        Log[1<<i]=i;
    }
    for(R int i=1,t=0;i<=maxn<<1;i++)
    {
        if(Log[i])
        {
            t=Log[i];continue;
        }
        Log[i]=t;
    }
    for(R int i=1;i<=m;i++)
    {
        readint(q1[i]);readint(q2[i]);
        lca[i]=Lca(q1[i],q2[i]);
    }
    prepare();
    solve();
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值