HNOI2015 接水果

Description

 
Input
Output
 
Sample Input
10 10 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338 
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1
Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
 
Data Constraint
 
 
 

我们考每个盘子对水果的影响。

每个盘子的路径,我们分两种情况讨论

1.a和b不构成祖先关系

 

那么它能影响的水果必须是起点在a或a的子树,终点在b或b的子树(起终点可调换)
2.a和b构成祖先关系
 那么起点必须在b或b的子树,终点在c的子树之外。
 
我们发现满足要求的起点或终点在dfs序中都是一段连续的区间
 
我们以起点为x轴,终点为y轴,建一个坐标系,我们发现每个盘子对点的要求都可以用一个矩形来表示,每个查询只是查询一点,查询包含它的权值第k小的矩形
我们可以用经典的扫描线问题来解决。
对于y轴,开一个树状数组套权值线段树,支持区间修改和点查询。
 
问题解决,时间复杂度O(Nlog2N)
 
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>

using namespace std;
map<int,int> H;

struct plt{
    int x,z,q;
}a[40011],ask[40011];

struct rec{
    int x,l,r,k,q,id;
}d[400011];

struct tree{
    int ls,rs,q;
}tr[32000001];

int ans[40011],g[40011],next[80011],y[80011],dfn[80011],size[80011];
int fa[40011][16],que[40011],num[40011],root[40011],dep[40011];
int T,tc,tot,ts,t,n,m,q,i,x,z,j,tt;

void star(int i,int j)
{
    tt++;
    next[tt]=g[i];
    g[i]=tt;
    y[tt]=j;
}

bool cmp(rec a,rec b)
{
    if(a.x==b.x)return a.k<b.k;
    else return a.x<b.x;
}

void dfs(int x)
{
    int j,k;
    size[x]=1;
    j=g[x];
    dfn[x]=++t;
    while(j!=0){
        k=y[j];
        if(k!=fa[x][0]){
            fa[k][0]=x;
            dep[k]=dep[x]+1;
            dfs(k);
            size[x]+=size[k];
        }
        j=next[j];
    }
}

int jump(int x,int z)
{
    int e;
    e=0;
    while(z){
        if(z%2==1)x=fa[x][e];
        z/=2;
        e++;
    }
    return x;
}

void newrec(int l,int r,int x,int y,int q)
{
    if(l>r||x>y)return;
    T++;
    d[T].x=l;d[T].l=x;d[T].r=y;d[T].k=0;d[T].q=q;
    T++;
    d[T].x=r;d[T].l=x;d[T].r=y;d[T].k=2;d[T].q=q;
    T++;
    d[T].x=x;d[T].l=l;d[T].r=r;d[T].k=0;d[T].q=q;
    T++;
    d[T].x=y;d[T].l=l;d[T].r=r;d[T].k=2;d[T].q=q;
}

void addrec(int x,int z,int q)
{
    int j,k;
    if(dep[x]>dep[z])swap(x,z);
    if(dfn[z]>=dfn[x]&&dfn[z]<dfn[x]+size[x]){
        k=jump(z,dep[z]-dep[x]-1);
        newrec(1,dfn[k]-1,dfn[z],dfn[z]+size[z]-1,q);
        newrec(dfn[k]+size[k],n,dfn[z],dfn[z]+size[z]-1,q);
        
    }
    else newrec(dfn[x],dfn[x]+size[x]-1,dfn[z],dfn[z]+size[z]-1,q);
}

int lowbit(int x)
{
    return x&-x;
}

void Insert(int &t,int l,int r,int x,int y)
{
    if(t==0)t=++tc;
    if(l==r){
        tr[t].q+=y;
        return;
    }
    int mid;
    mid=(l+r)/2;
    if(x<=mid)Insert(tr[t].ls,l,mid,x,y);
    if(x>mid)Insert(tr[t].rs,mid+1,r,x,y);
    tr[t].q=tr[tr[t].ls].q+tr[tr[t].rs].q;
}

void Ins(int l,int r,int y,int z)
{
    while(r){
        Insert(root[r],1,tot,y,z);
        r-=lowbit(r);
    }
    l--;
    while(l){
        Insert(root[l],1,tot,y,-z);
        l-=lowbit(l);
    }
}

int Find(int l,int r,int k)
{
    if(l==r)return num[l];
    int mid,i,chk;
    chk=0;
    mid=(l+r)/2;
    for(i=1;i<=ts;i++)chk+=tr[tr[que[i]].ls].q;
    if(chk>=k){
        for(i=1;i<=ts;i++)que[i]=tr[que[i]].ls;
        return Find(l,mid,k);
    }
    else{
        for(i=1;i<=ts;i++)que[i]=tr[que[i]].rs;
        return Find(mid+1,r,k-chk);
    }
}

int Ask(int x,int z)
{
    ts=0;
    while(x<=n){
        que[++ts]=root[x];
        x+=lowbit(x);
    }
    return Find(1,tot,z);
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    for(i=1;i<n;i++){
        scanf("%d%d",&x,&z);
        star(x,z);
        star(z,x);
    }
    dfs(1);
    for(i=1;i<=15;i++)
        for(j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&a[i].x,&a[i].z,&a[i].q);
        if(!H[a[i].q]){
            H[a[i].q]=1;
            num[++tot]=a[i].q;
        }
    }
    sort(num+1,num+1+tot);
    for(i=1;i<=tot;i++)H[num[i]]=i;
    for(i=1;i<=m;i++)a[i].q=H[a[i].q];
    for(i=1;i<=m;i++)addrec(a[i].x,a[i].z,a[i].q);
    for(i=1;i<=q;i++){
        scanf("%d%d%d",&ask[i].x,&ask[i].z,&ask[i].q);
        T++;
        d[T].x=dfn[ask[i].x];d[T].l=d[T].r=dfn[ask[i].z];d[T].k=1;d[T].id=i;d[T].q=ask[i].q;
    }
    sort(d+1,d+1+T,cmp);
    for(i=1;i<=T;i++){
        if(d[i].k==0)Ins(d[i].l,d[i].r,d[i].q,1);
        if(d[i].k==1)ans[d[i].id]=Ask(d[i].l,d[i].q);
        if(d[i].k==2)Ins(d[i].l,d[i].r,d[i].q,-1);
    }
    for(i=1;i<=q;i++)printf("%d\n",ans[i]);
}

 

转载于:https://www.cnblogs.com/applejxt/p/4450625.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值