BZOJ4009: [HNOI2015]接水果 解题报告

题目问两点间的路径上子路径权的第k小,一开始给出能做子路径的路径p[]和其权值



有一篇介绍的很详细的题解
http://www.cnblogs.com/mjy0724/p/4447813.html




看了思路知道怎么做会打的下面我写的东西都可以不看了


窝讲一下个人具体的做法(不会具体怎么做的可以看下)

这道题整体二分就是二分一个路径的权值,将当前考虑的矩阵按是否在二分的范围内分类拿出来,像归并排序那样把这个区间的矩阵编号重新排一下(这样往下二分时可以直接带编号区间下去)
然后扫描线扫一遍,求出每个点被多少个矩阵包含了,如果超出k那就把它扔到左边二分,否则扔到右边且k减去询问的答案(点也像矩阵那样重新排一遍),二分时就带二分区间、矩阵编号区间,点编号区间下去
窝不会区间修改的树状数组…打了线段树,每次二分线段树注意不能暴力清空不然复杂度就退化了,会T,询问到哪里清空到哪里(还有种做法是每次撤销掉之前的操作)

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

void read(int &x)
{
    char c;
    while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9')(x*=10)+=c-'0';
}
const int maxn = 81000;
const int maxd = 18;

struct edge{int y,next;}a[maxn];int len,fir[maxn];
void insert(int x,int y){len++;a[len].y=y;a[len].next=fir[x];fir[x]=len;}
struct plate
{
    int l,r,h,s,flag;
}p[maxn<<2],b[maxn<<2],br[maxn<<2]; int num;
struct node
{
    int x,y,id,k,ans;
}point[maxn],c[maxn],cr[maxn];
int dep[maxn],fa[maxn][maxd],dfn[maxn],nex[maxn],id;
int s[maxn],tree[maxn<<2];
int times[maxn<<2];
int n,m,Q,ts;

void dfs(int x)
{
    dfn[x]=++id;
    for(int i=1;i<=maxd;i++)
    {
        if((1<<i)>dep[x])break;
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    for(int k=fir[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x][0])
        {
            fa[y][0]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    }
    nex[x]=id;
}
int LCAson(int x,int y)
{
    if(dep[x]<dep[y]){int t=x;x=y;y=t;}
    for(int i=maxd-1;dep[x]!=dep[y]&&i>=0;i--)
        if(fa[x][i]&&dep[fa[x][i]]>dep[y])x=fa[x][i];
    if(fa[x][0]==y)return x;
    x=fa[x][0];
    for(int i=maxd-1;i>=0;i--)
        if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}
    return x;
}
void update(int x,int l,int r,int lx,int rx,int c)
{
    if(times[x]!=ts){tree[x]=0;times[x]=ts;}
    if(lx<=l&&r<=rx){tree[x]+=c;return ;}
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(rx<=mid)update(lc,l,mid,lx,rx,c);
    else if(lx>mid)update(rc,mid+1,r,lx,rx,c);
    else update(lc,l,mid,lx,mid,c),update(rc,mid+1,r,mid+1,rx,c);
}
int Query(int x,int l,int r,int loc)
{
    if(times[x]!=ts){tree[x]=0;times[x]=ts;}
    if(l==r)return tree[x];
    int ret=tree[x];
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid)return ret+Query(lc,l,mid,loc);
    else return ret+Query(rc,mid+1,r,loc);
}
void solve(int l,int r,int lp,int rp,int pl,int pr)
{
    if(pl>pr)return ;
    if(l==r)
    {
        for(int i=pl;i<=pr;i++) point[i].ans=s[l];
        return;
    }
    ts++;
    int mid=(l+r)>>1,midx=s[mid];
    int bn=0,brn=0,cn=0,crn=0;
    for(int i=lp;i<=rp;i++)
    {
        if(p[i].s<=midx) b[++bn]=p[i];
        else br[++brn]=p[i];
    }
    for(int i=1;i<=bn;i++) p[i+lp-1]=b[i];
    for(int i=1;i<=brn;i++) p[lp+bn-1+i]=br[i];
    int pos=pl;
    for(int i=1;i<=bn;i++)
    {
        while(pos<=pr&&point[pos].y<b[i].h)
        {
            int temp=Query(1,1,id,point[pos].x);
            if(temp>=point[pos].k) c[++cn]=point[pos];
            else
            {
                cr[++crn]=point[pos];
                cr[crn].k-=temp;
            }
            pos++;
        }
        update(1,1,id,b[i].l,b[i].r,b[i].flag);
    }
    while(pos<=pr)
    {
        int temp=Query(1,1,id,point[pos].x);
        if(temp>=point[pos].k) c[++cn]=point[pos];
        else
        {
            cr[++crn]=point[pos];
            cr[crn].k-=temp;
        }
        pos++;
    }
    for(int i=1;i<=cn;i++)point[pl+i-1]=c[i];
    for(int i=1;i<=crn;i++)point[pl+cn-1+i]=cr[i];
    solve(l,mid,lp,lp+bn-1,pl,pl+cn-1);
    solve(mid+1,r,lp+bn,rp,pl+cn,pr);
}
bool cmph(plate x,plate y){return x.h<y.h;}
bool cmp1(node x,node y){return x.y<y.y;}
bool cmp2(node x,node y){return x.id<y.id;}

int main()
{
    len=id=0;memset(fir,0,sizeof fir);
    read(n);read(m);read(Q);
    for(int i=1;i<n;i++)
    {
        int x,y;read(x);read(y);
        insert(x,y);insert(y,x);
    }
    dfs(1);
    num=0;
    for(int i=1;i<=m;i++)
    {
        int x,y;read(x);read(y);read(s[i]);
        if(dep[x]<dep[y]){int t=x;x=y;y=t;}
        int la=LCAson(x,y),fla=fa[la][0];
        if(fla==y)
        {
            num++;
            p[num].s=s[i];p[num].l=1;p[num].r=dfn[la]-1;
            p[num].h=dfn[x];p[num].flag=1;
            num++;
            p[num].s=s[i];p[num].l=1;p[num].r=dfn[la]-1;
            p[num].h=nex[x]+1;p[num].flag=-1;

            num++;
            p[num].s=s[i];p[num].l=dfn[x];p[num].r=nex[x];
            p[num].h=nex[la]+1;p[num].flag=1;
            /*num++;
            p[num].s=s[i];p[num].l=dfn[x];p[num].r=nex[x];
            p[num].h=id+1;p[num].flag=-1;*/
        }
        else
        {
            if(dfn[x]>dfn[y]){int t=x;x=y;y=t;}
            num++;
            p[num].s=s[i];p[num].l=dfn[x];p[num].r=nex[x];
            p[num].h=dfn[y];p[num].flag=1;
            num++;
            p[num].s=s[i];p[num].l=dfn[x];p[num].r=nex[x];
            p[num].h=nex[y]+1;p[num].flag=-1;
        }
    }
    sort(s+1,s+m+1);
    sort(p+1,p+num+1,cmph);
    for(int i=1;i<=Q;i++)
    {
        int x,y,k;read(x);read(y);read(k);
        if(dfn[x]>dfn[y]){int t=x;x=y;y=t;}
        point[i].x=dfn[x];point[i].y=dfn[y];
        point[i].id=i;point[i].k=k;
    }
    sort(point+1,point+Q+1,cmp1);
    ts=0; solve(1,m,1,num,1,Q);
    sort(point+1,point+Q+1,cmp2);
    for(int i=1;i<=Q;i++)printf("%d\n",point[i].ans);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值