bzoj3526[Poi2014]Card*

bzoj3526[Poi2014]Card

题意:

有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i]。有m个操作,第i个操作会交换c[i]和d[i]两个位置上的卡片。每次操作后,你都需要判断,通过任意翻转卡片(把正面变为反面或把反面变成正面,但不能改变卡片的位置),能否让卡片正面上的数从左到右单调不降。n≤200000,m≤1000000。

题解:

线段树每个节点维护对应区间若第一张卡片为较小一面得到的最后一张卡片的最小值以及若第一张卡片为较大一面得到的最后一张卡片的最小值(如果无法则为-1)。操作就对于普通线段树的单点修改。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 200010
 7 using namespace std;
 8 
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
12     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
13     return f*x;
14 }
15 int a[maxn],b[maxn],l[maxn*3],r[maxn*3],mn[maxn*3],mx[maxn*3],n,m;
16 void update(int x){
17     int lc=x<<1,rc=x<<1|1;
18     if(mn[lc]!=-1&&mn[rc]!=-1&&mn[lc]<=a[l[rc]])mn[x]=mn[rc];
19     else if(mn[lc]!=-1&&mx[rc]!=-1&&mn[lc]<=b[l[rc]])mn[x]=mx[rc];else mn[x]=-1;
20     if(mx[lc]!=-1&&mn[rc]!=-1&&mx[lc]<=a[l[rc]])mx[x]=mn[rc];
21     else if(mx[lc]!=-1&&mx[rc]!=-1&&mx[lc]<=b[l[rc]])mx[x]=mx[rc];else mx[x]=-1;
22 }
23 void build(int x,int bl,int br){
24     l[x]=bl; r[x]=br; if(bl==br){mn[x]=a[bl]; mx[x]=b[bl]; return;}
25     int mid=(bl+br)>>1; build(x<<1,bl,mid); build(x<<1|1,mid+1,br); update(x);
26 }
27 void modify(int x,int pos){
28     if(l[x]==r[x]){mn[x]=a[pos]; mx[x]=b[pos]; return;} int mid=(l[x]+r[x])>>1;
29     if(pos<=mid)modify(x<<1,pos);else modify(x<<1|1,pos); update(x);
30 }
31 int main(){
32     n=read(); inc(i,1,n){a[i]=read(); b[i]=read(); if(a[i]>b[i])swap(a[i],b[i]);}
33     build(1,1,n); m=read();
34     inc(i,1,m){
35         int c=read(),d=read(); int t1=a[c],t2=b[c];
36         a[c]=a[d]; b[c]=b[d]; modify(1,c); a[d]=t1; b[d]=t2; modify(1,d);
37         if(mn[1]==-1&&mx[1]==-1)puts("NIE");else puts("TAK");
38     }
39     return 0;
40 }

 

20161110

转载于:https://www.cnblogs.com/YuanZiming/p/6055412.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值