很有意思。是因为排序那道题才听闻今年tjoi2016的。

题是好题!先把它刷完再去把zhihu look through一遍。

bzoj4552

以后看到什么做不出的题,看看能否写二分!!!!写二分!!!!写二分!!!!!!!!

二分答案,大于mid的取一,否则为0,写的时候注意了一些细节,所以效率比较高。

二分的时候边界少打了个等于,下次要注意回来看边界!

膜鏼添动力--

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 400100
using namespace std;
int n,m,ans;
int tree[N],f[N],a[N],z[N],y[N],sum[N],op[N];
void push_down(int p,int st,int ed)
{
  );
  f[p+p]=f[p];f[p+p+]=f[p];
  tree[p+p]=f[p]-;tree[p+p+]=f[p]-;
  sum[p+p]=tree[p+p]*(mid-st+);sum[p+p+]=tree[p+p+]*(ed-mid);
  f[p]=;
}
int ask(int l,int r,int st,int ed,int p)
{
  if(l==st&&r==ed)return sum[p];push_down(p,st,ed);
  ;
  if(r<=mid)return ask(l,r,st,mid,p+p);else
   ,ed,p+p+);else
    ,r,mid+,ed,p+p+);
}
int find(int l,int st,int ed,int p)
{
  if(l==st&&l==ed)return tree[p];
  push_down(p,st,ed);
  ;
  if(l<=mid)return find(l,st,mid,p+p);else
   ,ed,p+p+);
}
void update(int l,int r,int st,int ed,int p,int v)
{
  if(l>r)return;
  ;
  if(l==st&&r==ed)
  {
    tree[p]=v;sum[p]=v*(ed-st+);f[p]=v+;
    return;
  }
  push_down(p,st,ed);
  if(r<=mid)update(l,r,st,mid,p+p,v);else
   ,ed,p+p+,v);else
   {
     update(l,mid,st,mid,p+p,v);update(mid+,r,mid+,ed,p+p+,v);
   }
  sum[p]=sum[p+p]+sum[p+p+];
}
void work(int now)
{
  memset(tree,,,,sizeof(sum));
  ;i<=n;i++),n,,);
  ;i<=m;i++)
  {
    int l=z[i],r=y[i];
    ,n,);//printf("now==%d %d\n",now,x);
    )
    {
         update(l,r-x,,n,,);update(r-x+,r,,n,,);//sheng xu
    }else
    {
        update(l,l+x-,,n,,);update(l+x,r,,n,,);//jiang xu
    }
  }
}
int main()
{
//freopen("4552.in","r",stdin);
  scanf("%d%d",&n,&m);
  ;i<=n;i++)scanf("%d",&a[i]);
  ;i<=m;i++)
   {
     scanf("%d%d%d",&op[i],&z[i],&y[i]);
   }
  int p;
  scanf(,r=n;
  while(l<=r)
  {
    ;
    work(mid);,n,);
    )l=mid+;;
    //printf("%d %d\n",l,r);
  }
  printf("%d",ans);
}

5/29

昨天晚上做了T1,bzoj4551 Tree

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 200010
using namespace std;
int n,m,edgenum,num;
int vet[N],next[N],ans[N],head[N],f[N],dis[N],s[N],fa[N],q[N];
void add(int u,int v)
{
  edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;
}
int find(int x)
{
  if  (f[x]!=x)f[x]=find(f[x]);return f[x];
}
void dfs(int u,int ff,int dep)
{
  int e=head[u];
  ))f[u]=ff;dis[u]=dep;//printf("%d %d\n",u,f[u]);
  )
  {
    int v=vet[e];
    )
    {
      fa[v]=u;dfs(v,u,dep+);
     }
    e=next[e];
  }
}
int main()
{
  scanf(]=;f[]=;fa[]=;s[]=;
  ;i<=n-;i++)
  {
    int u,v;
    scanf("%d%d",&u,&v);add(u,v);add(v,u);
  }
  ;i<=m;i++)
  {
    ];
    scanf("%s%d",st,&q[i]);
    ]=='Q')q[i]=-q[i];else f[q[i]]=q[i],s[q[i]]++;
  }
  dfs(,,);
  ;i--)
  {
    )
    {
      num++,ans[num]=find(-q[i]);
    }else
     {
       int x=q[i],y=find(fa[x]);s[x]--;
       )f[x]=y;
     }
  }
  ;i--)printf("%d\n",ans[i]);
} 

4553: [Tjoi2016&Heoi2016]序列

看懂了题意的限制后,就可以知道,若要i可以排在j的前面;只要满足r[i]<=a[j],a[i]<=L[j]即可。

秒yy了一个二分求不下降子序列的方法发现不可以,why?

因为它的限制条件是二维的,无法描述谁比谁更优。---此时就需要求助于cdq分治了

听说要小心写,否则容易写出暴力。

然后这里写的时候有两个需要注意的点,清空树状数组的时候不要偷懒写memset,这样就是暴力了,(个人被坑了好几次)。

还有就是当l==r的时候,切记不要将它直接赋值为1,它是有价值的qaq!

其它就没什么了,将每个点的答案看作一组询问,将询问二分,处理左边和右边,再处理左边对右边的影响,不会分析复杂度

反正是nlognlogn的。。。 以后写题的时候记住cdq的这个思想。。就好了(摔)

#include<cstdio>
#define inf 1000000000
#include<algorithm>
#include<cstring>
#define N 100100
using namespace std;
int L[N],c[N],a[N],R[N],ans[N];
int Ans,n,m;
struct g{
  int l,r,id;
}d[N];
bool cmp(g a,g b)
{
  if(a.l==b.l)return a.id<b.id;return a.l<b.l;
}
void cc(int x,int v)
{
  ;i+=i&(-i))
    {

      c[i]=max(c[i],v);)c[i]=;
    }
}
int get(int x)
{
  ;
  ;i-=i&(-i))
  {
    t=max(t,c[i]);
  }return t;
}
void solve(int l,int r)
{
  );return;}
  ;
  solve(l,mid);
  for(int i=l;i<=r;i++)
  {
    if(i<=mid)
    {
      d[i].l=a[i];d[i].r=R[i];
    }else
    {
      d[i].l=L[i];d[i].r=a[i];
    }
    d[i].id=i;
  }
  sort(d+l,d++r,cmp);
  for(int i=l;i<=r;i++)
   if(d[i].id<=mid)cc(d[i].r,ans[d[i].id]);
  );
  for(int i=l;i<=r;i++)
   );
  solve(mid+,r);
}
int main()
{
  scanf("%d%d",&n,&m);
  ;i<=n;i++) scanf("%d",&a[i]),L[i]=R[i]=a[i];
  int x,y;
  ;i<=m;i++)
  {
    scanf("%d%d",&x,&y);
    if(y<L[x])L[x]=y;if(y>R[x])R[x]=y;
  }
  solve(,n);;i<=n;i++)if(ans[i]>Ans)Ans=ans[i];
  printf("%d\n",Ans);
} 

bzoj4554[Game]

【claim again! you Musn't look through any solution every time when possible!】

对于n<=50,可以有很多思路。。。暴搜(这个稍微靠谱点儿)。。分治。。dp?

做题的时候最好先想想简单条件下的题目可以怎么做啊!!!!(二分都想不到真是受不了自己了)

二分图复杂度O(V*E),因为有硬石头,然后就可以轻易拆行(列) 了。

以前在212训练联赛题的时候做过一道类似的二分图匹配,横的竖的切一切,就是泥泞的牧场!!!

oh my god...我到底是当时做题太不走心还是现在智商+记忆直线下降啊。。。。。。。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10000
using namespace std;
][];
][],y[][],next[N],vet[N],head[N],flag[N],match[N];
void add(int u,int v)
{
  edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;
  //printf("%d %d\n",u,v);
}
int dfs(int u)
{
  ;
  )
  {
    int v=vet[e];
    ||(flag[match[v]]==&&dfs(match[v])==))
    {
      match[v]=u;
      ;
     }
    e=next[e];
  };
}
int main()
{
  scanf("%d%d",&n,&m);
  ;i<=n;i++)
  {
    scanf();
  }
  ,B=;
  ;i<=n;i++)
  {
    ;j<=m;j++)
    {
      if(st[i][j]=='#')A++;x[i][j]=A;
    }A++;
  }
  ;j<=m;j++)
  {
    ;i<=n;i++)
    {
      if(st[i][j]=='#')B++;y[i][j]=B;
    }B++;
  }
  ;i<=n;i++)
    ;j<=m;j++)
    if(st[i][j]=='*')
    {
      int u=x[i][j],v=y[i][j];add(u,v);
    }
  ;i<=A;i++)
  {
    memset(flag,,sizeof(flag));
    ans+=dfs(i);
  }
  printf("%d",ans);
} 

【bzoj4555】

NTT %%%NiroBC

感觉这辈子都不用做这道题了。。。

【Bzoj4556】

SAM..........orz

04-24 22:50