矮人排队
jzoj (gz)3236
题目大意:
有n个人,高度分别为1,2……n(高度按输入来看),现在有两种操作
1:把第x个人和第y个人换一下
2:询问高度为A,A+1……B这B-A+1个人是否站在一起
输入样例#1:
5 3
2 4 1 3 5
2 2 5
1 3 1
2 2 5
输出样例#1:
NO
YES
输入样例#2:
7 7
4 7 3 5 1 2 6
2 1 7
1 3 7
2 4 6
2 4 7
2 1 4
1 1 4
2 1 4
输出样例#2:
YES
NO
YES
NO
YES
数据范围
50%的数据:类型2询问中A,B满足B−A≤50B-A≤50B−A≤50
100%的数据:1≤X,Y≤N,X≠Y,1≤A≤B≤N,2≤N≤200,000,2≤M≤200,000。1≤X,Y≤N,X≠Y,1≤A≤B≤N,2≤N≤200,000,2≤M≤200,000。1≤X,Y≤N,X̸=Y,1≤A≤B≤N,2≤N≤200,000,2≤M≤200,000。
解题思路:
首先一看就知道是线段树
但因为查询的是高度,所以我们线段树的下标是高度而不是位置,而存的就是位置,这样当查询时,求出高度为A到B这些人中的位置最大和最小,然后看一看这两个数相减是不是B-A+1即可
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,u,x,y,maxans,minans,a[200500],w[200500];
struct rec
{int l,r,maxx,minn;
}tree[1600500];
void up(int dep)//上传
{tree[dep].maxx=max(tree[dep*2].maxx,tree[dep*2+1].maxx);tree[dep].minn=min(tree[dep*2].minn,tree[dep*2+1].minn);
}
void make(int dep)//建树
{if (tree[dep].l==tree[dep].r){tree[dep].maxx=a[tree[dep].l];tree[dep].minn=a[tree[dep].l];return;}int mid=(tree[dep].l+tree[dep].r)>>1;tree[dep*2].l=tree[dep].l,tree[dep*2].r=mid;tree[dep*2+1].l=mid+1,tree[dep*2+1].r=tree[dep].r;make(dep*2);make(dep*2+1);up(dep);
}
int find(int dep,int l)
{if (tree[dep].l==l&&tree[dep].r==l) return tree[dep].maxx;int mid=(tree[dep].l+tree[dep].r)>>1;if (l<=mid) return find(dep*2,l);else return find(dep*2+1,l);
}
void change(int dep,int l,int s)
{if (tree[dep].l==l&&tree[dep].r==l){tree[dep].maxx=tree[dep].minn=s;return;}if (tree[dep].l>=tree[dep].r) return;int mid=(tree[dep].l+tree[dep].r)>>1;if (l<=mid) change(dep*2,l,s);else change(dep*2+1,l,s);up(dep);
}
void swapp(int x1,int y1)
{change(1,w[x1],y1);//第x1个人变为y1,因为是坐标是高度,所以要用wchange(1,w[y1],x1);swap(w[x1],w[y1]);//交换
}
void answer(int dep,int l,int r)//查询
{if (tree[dep].l==l&&tree[dep].r==r){maxans=max(maxans,tree[dep].maxx);minans=min(minans,tree[dep].minn);return;}if (tree[dep].l>=tree[dep].r) return;int mid=(tree[dep].l+tree[dep].r)>>1;if (r<=mid){answer(dep*2,l,r);return;}if (l>mid){answer(dep*2+1,l,r);return;}answer(dep*2,l,mid);answer(dep*2+1,mid+1,r);return;
}
int main()
{scanf("%d %d",&n,&m);for (int i=1;i<=n;++i){scanf("%d",&w[i]);//第i个人的高度a[w[i]]=i;//高度为w[i]的人的位置}tree[1].l=1;tree[1].r=n;make(1);for (int i=1;i<=m;++i){scanf("%d %d %d",&u,&x,&y);if (u&1) swapp(x,y);//交换else{minans=2147483647;maxans=0;answer(1,x,y);if (maxans-minans+1==y-x+1) printf("YES\n");//判断长度是否一样else printf("NO\n");}}
}