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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值