bzoj3734 [Ontak2013]Miny

传送门

学长测试题原题。
题解:神奇的线段树优化建图+拓扑排序。
对于一个地雷来说,我们可以在将所有地雷按照坐标排序后二分得到所能引爆的地雷区间,然后从可以被其引爆的地雷向其连单向边,这个可以用线段树优化建图来搞;为了统计答案,我们还要维护每个点所能控制的区间端点的位置。最后用拓扑排序更新每个点所能引爆的最大区间,统计答案即可。

ps:RE的是由于爆栈了……学长的数据还是太弱

CODE:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=110005;
struct node
{
    ll x,r;
    int id;
    inline bool operator <(const node &other)const{return x<other.x;}
}bomb[N];
struct edge
{
    int nxt,to;
}a[N<<4],e[N<<4];
int s[N<<2],top;
bool b[N<<2];
int head[N<<2],Head[N<<2];
int dfn[N<<2],low[N<<2],belong[N<<2],in[N<<2],pos[N<<2],left[N<<2],right[N<<2],l[N<<2],r[N<<2],ans[N<<2];
ll tmp[N<<2];
int T,n,m,num,Num,Time,block,tot;
queue<int> q;
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
inline void add(int x,int y)
{
    a[++num].nxt=head[x],a[num].to=y,head[x]=num;
}
inline void Add(int x,int y)
{
    e[++Num].nxt=Head[x],e[Num].to=y,Head[x]=Num;
}
void build(int l,int r,int now)
{
    left[now]=l,right[now]=r;
    if(now!=1) add(now,now>>1);
    if(l==r){pos[l]=now;tot=max(tot,now);return;}
    int mid=(l+r)>>1;
    build(l,mid,now<<1);
    build(mid+1,r,now<<1|1);
}
void insert(int L,int R,int l,int r,int now,int num)
{
    if(L<=l&&r<=R){if(num!=now)add(now,num);return;}
    int mid=(l+r)>>1;
    if(L<=mid) insert(L,R,l,mid,now<<1,num);
    if(R>mid) insert(L,R,mid+1,r,now<<1|1,num);
}
void dfs(int now)
{
    dfn[now]=low[now]=++Time;
    s[++top]=now;b[now]=1;
    for(int i=head[now];i;i=a[i].nxt)
      if(!dfn[a[i].to])
      {
        dfs(a[i].to);
        low[now]=min(low[now],low[a[i].to]);
      }
      else if(b[a[i].to]) low[now]=min(low[now],dfn[a[i].to]);
    if(dfn[now]==low[now])
    {
        int tmp;
        l[++block]=1e9;
        r[block]=0;
        do tmp=s[top--],b[tmp]=0,belong[tmp]=block,l[block]=min(l[block],left[tmp]),r[block]=max(r[block],right[tmp]);
        while(tmp!=now);
    }
}
inline void topologysort()
{
    for(int i=1;i<=block;i++)
      if(!in[i]) q.push(i);
    while(!q.empty())
    {
        int tmp=q.front();q.pop();
        for(int i=Head[tmp];i;i=e[i].nxt)
        {
            in[e[i].to]--;
            l[e[i].to]=min(l[e[i].to],l[tmp]);
            r[e[i].to]=max(r[e[i].to],r[tmp]);
            if(!in[e[i].to]) q.push(e[i].to);
        }
    }
}
int main()
{
    int sz=32<<20; 
    char *p=(char*)malloc(sz)+sz;  
    __asm__("movl %0, %%esp\n"::"r"(p)); 
    scanf("%d",&T);
    while(T--)
    {
        num=Num=Time=block=tot=0;
        scanf("%d",&n);
        memset(dfn,0,sizeof(int)*(n<<2));
        memset(low,0,sizeof(int)*(n<<2));
        memset(head,0,sizeof(int)*(n<<2));
        memset(Head,0,sizeof(int)*(n<<2));
        memset(left,0,sizeof(int)*(n<<2));
        memset(right,0,sizeof(int)*(n<<2));
        for(int i=1;i<=n;i++)
          scanf("%lld%lld",&bomb[i].x,&bomb[i].r),bomb[i].id=i;
        sort(bomb+1,bomb+n+1);
        for(int i=1;i<=n;i++)
          tmp[i]=bomb[i].x;
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            int l=lower_bound(tmp+1,tmp+n+1,tmp[i]-bomb[i].r)-tmp;
            int r=upper_bound(tmp+1,tmp+n+1,tmp[i]+bomb[i].r)-tmp-1;
            if(l!=r) insert(l,r,1,n,1,pos[i]);
        }
        for(int i=1;i<=tot;i++)
          if(!dfn[i]) dfs(i);
        for(int i=1;i<=tot;i++)
          for(int j=head[i];j;j=a[j].nxt)
            if(belong[i]!=belong[a[j].to]) Add(belong[i],belong[a[j].to]),in[belong[a[j].to]]++;
        topologysort();
        for(int i=1;i<=n;i++)
          ans[bomb[i].id]=r[belong[pos[i]]]-l[belong[pos[i]]]+1;
        for(int i=1;i<n;i++)
          printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
    return 0;
}

犯下的错误:将每个实点的贡献设为1,拓扑排序时累加贡献,导致贡献重复累加。

输入:
1
5
48 4
8 3
-5 4
10 1
13 5

正确答案:
1 2 1 1 3

错误答案:
1 2 1 1 4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值