有向无环图,走到一个能够更新当前走过的点标号最大值的点,就可以加一或者减一。求每次都加能加最多,每次都减能减最少。
有趣的题目,满脑子都是哈尔滨重现了!!
这种思维题比哈尔滨 I I I简单一点,但是我依然没想出来,虽然已经特别接近了。
要求找到一个策略:
首先肯定要是拓扑序的走,那么队列有多个点,应该选哪一个呢?
当前最大值为 M M M,如果比 M M M小的点,可以随便放,显然不会影响结果还可以增加选择。
如果是前者,加最多的话,接下来要选的尽可能小。
如果是后者,减最少的话,接下来的要选的尽可能大,但是要先做最前面的操作。
这正是我所忽略的,因为前面的操作可能会产生更大的点。
#include
using namespace std;
vector<int> v;
const int maxn = 5e5+400;
typedef long long ll;
struct node1{
int x;
friend bool operator < (node1 a,node1 b){
return a.x>b.x;
}
};
struct node2{
int x;
friend bool operator < (node2 a,node2 b){
return a.x<b.x;
}
};
priority_queue<node1,vector<node1> >p;
set<int>q;
int n,m;
int ind[maxn],inq[maxn];
int ans1,ans2;
vector<int>G[maxn];
void topo1(){
for(int i=1;i<=n;i++){
if(ind[i])continue;
p.push(node1{i});
}
int now=0;
while(!p.empty()){
int u=p.top().x;p.pop();
if(u>now)ans1++;
now=max(now,u);
for(auto v:G[u]){
ind[v]--;
if(!ind[v])p.push(node1{v});
}
}
cout<<ans1<<endl;
}
void topo2(){
for(int i=1;i<=n;i++){
if(inq[i])continue;
q.insert(i);
}
int now=0;
while(!q.empty()){
int u;
if(*q.begin()<now){
u=*q.begin();
q.erase(u);
}
else{
u=*(--q.end());
q.erase(u);
}
if(u>now)ans2++;
now=max(now,u);
for(auto v:G[u]){
inq[v]--;
if(!inq[v])q.insert(v);
}
}
cout<<ans2<<endl;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
ind[v]++,inq[v]++;
}
topo1();
topo2();
}
有个排列 p p p,有一个序列 a a a,要求支持对 a a a的单点修改,询问区间内存不存在,对于区间内一个点, p [ a [ i ] ] p[a[i]] p[a[i]]也出现在这个区间内
有一说一 一般这都是套路题,首先对于每个点作为 p p p的时候,只有最近的有效,左边最近和右边最近,这都是可以预处理出来的。
那怎么处理修改呢?
修改的操作我们考虑到,实际上对于每个 a a a,其他的 p p p显然是最近的有效,其他的可以不更新,这样更新就可以在多项式复杂度内解决了。
细节较多。
具体怎么更新一个点呢,更新的时候要保证最近,所以首先找到离自己最近的点,比如找左边的,当前位置为5,值 3 3 3,最近的 3 3 3的位置为2,那么找到的最近 p [ 3 ] p[3] p[3]只有超过 2 2 2的时候才是最近的,才需要更新。
总之是比较复杂的,不过对于 a a a也只有这两种情况,也不是很复杂,只是最后一种情况一开始忽略了。
#include
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn = 500050;
typedef long long ll;
inline int read(){
int num=0,w=0;
char ch=0;
while(!isdigit(ch)){
w|=ch=='-';
ch=getchar();
}
while(isdigit(ch)){
num=(num<<3)+(num<<1)+(ch^48);
ch=getchar();
}
return w?-num:num;
}
int n,m,T=1;
int p[maxn],a[maxn],t[maxn];
set<int>s[maxn];
struct tree2{
tree2 *lson,*rson;
int val1,val2;
}dizhi[maxn<<1],*root=&dizhi[0];
void push_up(tree2 *tree){
tree->val1=max(tree->lson->val1,tree->rson->val1);//Left Point
tree->val2=min(tree->lson->val2,tree->rson->val2);//Right Point
}
void build(tree2 *tree,int l,int r){
tree->val1=0;
tree->val2=n+1;
if(l==r)return ;
int mid=(l+r)>>1;
tree->lson=&dizhi[T++];
tree->rson=&dizhi[T++];
build(tree->lson,l,mid);
build(tree->rson,mid+1,r);
}
void update(tree2 *tree,int l,int r,int pos,int val,int op){
if(l==r){
if(op==1)tree->val1=val;
if(op==2)tree->val2=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)update(tree->lson,l,mid,pos,val,op);
else update(tree->rson,mid+1,r,pos,val,op);
push_up(tree);
}
int get_val(tree2 *tree,int l,int r,int x,int y,int op){
if(x<=l&&r<=y){
if(op==1)return tree->val1;
if(op==2)return tree->val2;
}
int mid=(l+r)>>1;
int t1,t2;
if(op==1)t1=t2=0;
if(op==2)t1=t2=n+1;
if(x<=mid)t1=get_val(tree->lson,l,mid,x,y,op);
if(y>mid)t2=get_val(tree->rson,mid+1,r,x,y,op);
if(op==1)return max(t1,t2);
if(op==2)return min(t1,t2);
}
void deal_set(int x,int y){
s[a[x]].erase(x);
a[x]=y;
s[a[x]].insert(x);
}
void slove(int pos,int op){
set<int>::iterator it,iter;
if(op==1){
int LT=-1,v;
it=s[a[pos]].lower_bound(pos);
if(it!=s[a[pos]].begin())LT=*(--it);
iter=s[p[a[pos]]].upper_bound(pos);
if(iter!=s[p[a[pos]]].begin()){
v=*(--iter);
if(v>LT)update(root,1,n,pos,v,1);
}
}
else{
int RT=n+1,v;
it=s[a[pos]].upper_bound(pos);
if(it!=s[a[pos]].end())RT=*it;
iter=s[p[a[pos]]].lower_bound(pos);
if(iter!=s[p[a[pos]]].end()){
v=*iter;
if(v<RT)update(root,1,n,pos,v,2);
}
}
}
int main(){
cin>>n>>m;
build(root,1,n);
for(int i=1;i<=n;i++)p[i]=read(),t[p[i]]=i;
for(int i=1;i<=n;i++)a[i]=read(),s[a[i]].insert(i);
for(int i=1;i<=n;i++)slove(i,1),slove(i,2);
for(int i=1;i<=m;i++){
int op=read(),x=read(),y=read();
if(op==1){
set<int>::iterator re;
int L=0,R=0,wl=0,wr=0;
re=s[a[x]].lower_bound(x);
if(re!=s[a[x]].begin()){
wl=*(--re);
}
re=++s[a[x]].lower_bound(x);
if(re!=(s[a[x]].end())){
wr=*(re);
}
set<int>::iterator tl,tr;
int tmp=t[a[x]];
tl=s[tmp].upper_bound(x);
if(tl!=s[tmp].begin()){
L=*(--tl);
update(root,1,n,L,n+1,2);
}
tr=s[tmp].lower_bound(x);
if(tr!=s[tmp].end()){
R=*tr;
update(root,1,n,R,0,1);
}//删除原来a[x]的影响,只考虑最近的点对。
deal_set(x,y);
if(wl)slove(wl,2);
if(wr)slove(wr,1);
if(L)slove(L,2);
if(R)slove(R,1);
update(root,1,n,x,0,1);
update(root,1,n,x,n+1,2);
slove(x,1),slove(x,2);
L=0,R=0;
tmp=t[a[x]];
tl=s[tmp].upper_bound(x);
if(tl!=s[tmp].begin()){
L=*(--tl);
slove(L,2);
}
tr=s[tmp].lower_bound(x);
if(tr!=s[tmp].end()){
R=*tr;
slove(R,1);
}
//for(int i=1;i<=n;i++)cout<
}
else{
if(get_val(root,1,n,x,y,1)>=x||get_val(root,1,n,x,y,2)<=y)puts("Yes");
else puts("No");
}
}
}