• [HNOI2017]影魔


    标签:线段树

    题解:

      首先对于题目的条件进行分析,p1的条件是一个区间的两个端点必须是这一个区间的最大与次大值。p2的条件是一个区间的一个端点是最大值,而另一个端点不是次大值。显然,他们都需要两个条件(对于两个端点都有要求,这样的话不太好操作)。感受一下,p1的条件更为严苛,于是我们这样考虑:
      一个区间的一个端点是最大值(两个条件的公共部分),另一个不管,此时加上p2的贡献。
      我们可以通过线段树求解出这一个东西。对于i,找到右边大于他的第一个数,如果没有,自然是最后一个数,但是这样不好,于是我们加一个第n+1个数为+∞。然后设ri为右边大于他的第一个数,那么[i,i+1]、[i,i+2]、......[i,ri]都符合条件,于是在线段树中对于[i+1,ri]都+=p2。对于全部询问排序,给以i为左端点的区间加上贡献,查询[i+1,R]的和。反过来再搞一遍,注意询问区间也要反过来。
      然后我们发现题目中的对另一个端点的限制是互补的,我们的区间[i,ri]满足p1,而[i,i+1~ri-1]满足p2。因为只有一个满足p1,而且一个i对应一个ri,于是我们在ri处+p1-p2-p2即可,完美解决这一个问题。
    小结:此题关键在于两个条件有一半相同,而另一半互补,所以可以不管互补的那一半到时候再考虑。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #define ls k*2
      6 #define rs (k*2+1)
      7 #define LL long long
      8 using namespace std;
      9 const int MAXN=210000;
     10 int n,m,p1,p2,tp;
     11 int v[MAXN],aft[MAXN],st[MAXN];
     12 LL ans[MAXN],sum[MAXN*5],lz[MAXN*5];
     13 struct ed
     14 {
     15   int L,R,id;
     16 }ask[MAXN];
     17 #define down()
     18 {
     19   sum[ls]+=lz[k]*(mid-ll+1);
     20   sum[rs]+=lz[k]*(rr-mid);
     21   lz[ls]+=lz[k];
     22   lz[rs]+=lz[k];
     23   lz[k]=0;
     24 }
     25 inline int gi() {int res; scanf("%d",&res); return res;}
     26 bool comp(ed x,ed y){return x.L<y.L;}
     27 int find(int x)
     28 {
     29   int L=1,R=m,mid;
     30   while(L<=R)
     31     {
     32       mid=(L+R)/2;
     33       if(ask[mid].L<x)
     34         L=mid+1;
     35       else
     36         R=mid-1;
     37     }
     38   return L;
     39 }
     40 void add(int k,int ll,int rr,int L,int R,LL Val)
     41 {
     42   if(ll==L && rr==R)
     43     {
     44       sum[k]+=Val*(rr-ll+1);
     45       lz[k]+=Val;
     46       return;
     47     }
     48   int mid=(ll+rr)/2;
     49   down();
     50   if(R<=mid)
     51     add(ls,ll,mid,L,R,Val);
     52   else if(mid<L)
     53     add(rs,mid+1,rr,L,R,Val);
     54   else
     55     {
     56       add(ls,ll,mid,L,mid,Val);
     57       add(rs,mid+1,rr,mid+1,R,Val);
     58     }
     59   sum[k]=sum[ls]+sum[rs];
     60 }
     61 LL query(int k,int ll,int rr,int L,int R)
     62 {
     63   if(ll==L && rr==R) return sum[k];
     64   int mid=(ll+rr)/2;
     65   down();
     66   if(R<=mid)
     67     return query(ls,ll,mid,L,R);
     68   else if(mid<L)
     69     return query(rs,mid+1,rr,L,R);
     70   else
     71     return query(ls,ll,mid,L,mid)+query(rs,mid+1,rr,mid+1,R);
     72 }
     73 void work()
     74 {
     75   tp=0; st[0]=n+1;
     76   for(int i=n;i>=1;i--)
     77     {
     78       while(tp && v[st[tp]]<v[i]) tp--;
     79       aft[i]=st[tp];
     80       st[++tp]=i;
     81     }
     82   memset(sum,0,sizeof sum);
     83   memset(lz,0,sizeof lz);
     84   for(int i=n;i>=1;i--)
     85     {
     86       if(aft[i]>i)
     87         {
     88           add(1,1,n+1,i+1,aft[i],p2);
     89           add(1,1,n+1,aft[i],aft[i],p1-2*p2);
     90         }
     91       int p=find(i);
     92       while(ask[p].L==i)
     93         {
     94           ans[ask[p].id]+=query(1,1,n+1,i+1,ask[p].R);
     95           p++;
     96         }
     97     }
     98 }
     99 int main()
    100 {
    101   n=gi();m=gi();p1=gi();p2=gi();
    102   for(int i=1;i<=n;i++) v[i]=gi();
    103   for(int i=1;i<=m;i++) ask[i].L=gi() , ask[i].R=gi() , ask[i].id=i;
    104   sort(ask+1,ask+1+m,comp);
    105   work();
    106   reverse(v+1,v+1+n);
    107   for(int i=1;i<=m;i++)
    108     {
    109       swap(ask[i].L,ask[i].R);
    110       ask[i].L=n-ask[i].L+1;
    111       ask[i].R=n-ask[i].R+1;
    112     }
    113   sort(ask+1,ask+1+m,comp);
    114   work();
    115   for(int i=1;i<=m;i++)
    116     printf("%lld
    ",ans[i]);
    117   return 0;
    118 }
  • 相关阅读:
    关于ActionScript中那些你不知道的事情
    Flash Player 11 Stage3D学习大杂烩
    Qt 控制台输入输出(支持中文)
    Redis消息发布订阅的稳定性验证结论
    C++11 Lambda表达式(匿名函数)用法详解
    vue中“:”、“.”、“@”意义
    QT中printf输出不同步的解决办法
    QT5中使用SQLite
    QT 调用user32.dll移动鼠标
    10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(net,net core,C#)
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7922500.html
Copyright © 2020-2023  润新知