码迷,mamicode.com
首页 > 其他好文 > 详细

jxoi2017

时间:2018-08-21 11:37:44      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:题解   题目   需要   难度   nbsp   pac   clu   ret   space   

题解:

并不知道题目顺序就按照难度排序了

[JXOI2017]加法

这是一道很简单的贪心

最小值最大二分答案

然后我们可以从左向右考虑每一个位置

如果他还需要+A

我们就从能覆盖它的区间中挑一个最右的

正确性比较显然

暴力是n^2logn*T的 可能比较虚

会发现覆盖操作可以用线段树维护,查询最右可以使用堆

n*logn^2*T

 [JXOI2017]颜色

写的复杂了。。

正解比较简单

枚举右端点i,确定左端点j的可行位置

我们会发现,

对于maxv<=i,那么maxv>=j>=minv是不可行的

对于maxv>i,那么1<=j<=minv是不可行的

于是问题就变成了区间+1,区间-1,查询为0的个数

网上好像都是利用这个是1-x的所以变成从左到右枚举然后优先队列解决的

其实我们可以通过维护最小值个数,最小值来直接实现

我的方法是对于每一种颜色

我们可行的方案是在两个颜色空当之中,或者1个在最左边,1个在最右边

于是问题变成了n次覆盖一个矩形,最后查询矩形中为k的个数(其实查为0就和上面一样了)

注意区间2-1这样的是不符合的 所以可以先给不符合的-1

然后我们可以利用扫描线+线段树解决

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
#define me(x) memset(x,0,sizeof(x))
#define mid ((h+t)/2)
char ss[1<<24],*A=ss,*B=ss;
IL char gc()
{
  return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; 
}
template<class T>IL void read(T &x)
{
  rint f=1,c; while (c=gc(),c<48||c>57) if (c==-) f=-1; x=(c^48);
  while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
}
const int N=4e5+10;
const int N2=N*4;
int cnt;
struct re{
  int a,b,c,d;
}p[N*5];
int maxa[N2],lazy[N2],data[N2],a[N];
vector<int> ve[N];
IL void change(int h1,int t1,int h2,int t2,int k)
{
  p[++cnt].a=h1,p[cnt].b=h2,p[cnt].c=t2,p[cnt].d=k;
  p[++cnt].a=t1+1,p[cnt].b=h2,p[cnt].c=t2,p[cnt].d=-k;
}
IL bool cmp(re x,re y)
{
  return(x.a<y.a);
}
void build(int x,int h,int t)
{
  maxa[x]=0; data[x]=t-h+1; lazy[x]=0;
  if (h==t) return;
  build(x*2,h,mid); build(x*2+1,mid+1,t);
}
int cnt2=0;
void insert(int x,int h,int t,int h1,int t1,int k)
{
  if (h1>t1) return;
  if (h1<=h&&t<=t1)
  {
    maxa[x]+=k; lazy[x]+=k; return;
  }
  if (lazy[x])
  {
    maxa[x*2]+=lazy[x]; maxa[x*2+1]+=lazy[x];
    lazy[x*2]+=lazy[x]; lazy[x*2+1]+=lazy[x];
    lazy[x]=0;
  }
  if (h1<=mid) insert(x*2,h,mid,h1,t1,k);
  if (mid<t1) insert(x*2+1,mid+1,t,h1,t1,k);
  int t11=maxa[x*2],t22=maxa[x*2+1];
  if (t11<t22) maxa[x]=t22,data[x]=data[x*2+1];
  else if (t11>t22) maxa[x]=t11,data[x]=data[x*2];
  else maxa[x]=t11,data[x]=data[x*2+1]+data[x*2];
}
int main()
{
  int T,n;
  read(T);
  rep(ttt,1,T)
  {
    read(n);
    rep(i,1,n) ve[i].clear();
    int m=0;
    rep(i,1,n)
    {
      read(a[i]);
      m=max(a[i],m);
      ve[a[i]].push_back(i);
    }
    int k=m; cnt=0;
    rep(i,1,m)
    {
      if (!ve[i].size())
      { 
        k--; continue;
      }
      change(1,ve[i][0],ve[i][ve[i].size()-1],n,1);
      int tmp=(int)(ve[i].size())-2;
      rep(j,0,tmp)
        change(ve[i][j]+1,ve[i][j+1]-1,ve[i][j]+1,ve[i][j+1]-1,1);
      change(1,ve[i][0]-1,1,ve[i][0]-1,1);
      change(ve[i][ve[i].size()-1]+1,n,ve[i][ve[i].size()-1]+1,n,1);
    }
    rep(i,2,n)
    {
      change(i,i,1,i-1,-1);
    }
    sort(p+1,p+cnt+1,cmp);
    ll ans=0;
    build(1,1,n);
    rint j=1;
    rep(i,1,n)
    {
      while (j<=cnt&&p[j].a<=i) insert(1,1,n,p[j].b,p[j].c,p[j].d),j++;
      if (maxa[1]==k) ans+=data[1];
    }
    printf("%lld\n",ans);
  }
  return 0; 
}

 

jxoi2017

标签:题解   题目   需要   难度   nbsp   pac   clu   ret   space   

原文地址:https://www.cnblogs.com/yinwuxiao/p/9510183.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!