开场看A,发现不太会做。
猜结论,猜了个后10min才发现反例。
然后发现只要从小到大把每个数删掉后用并查集维护就是个区间数颜色。
写完后就过了。
差点栽倒在这个普及组题目上
然后在B上搞了整场,发现答案和奇偶最短路有关系。
然后建出最短路数组后想贪心,结果一整场都没搞出来。
最后只有110分。
总结:
由于对图论不擅长所以在B上出现重大失误,搞了很久,没有得到高分。
在括号路径这题上,我想到了正解所需要的所有性质,但是却没有做出。
要练习更多图论的题。
题解:
A:
签到题,普及组送分题。
考虑如何计算一个区间的答案。
考虑从大到小添加每种数。
设(ans)表示答案。
会发现(ans+=)包含当前数的连通块个数。
连通块用并查集维护。
然后就是个区间数颜色,可以bit。
#include<bits/stdc++.h>
using namespace std;
#define N 200010
int n,q,c[N],f[N],bt[N],ct,st[N],tp,vi[N],la[N],ans[N],mx;
vector<int>v[N],g[N];
struct no{
int l,id;
};
vector<no>qu[N];
int fd(int x){
return !f[x]?x:f[x]=fd(f[x]);
}
void ad(int x,int y){
for(;x<=n;x+=x&-x)
bt[x]+=y;
}
int qv(int x){
int r=0;
for(;x;x-=x&-x)
r+=bt[x];
return r;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
v[x].push_back(i);
mx=max(x,mx);
}
for(int i=1;i<=q;i++){
int x,y;
scanf("%d%d",&x,&y);
qu[y].push_back((no){x,i});
}
for(int i=mx;i;i--){
for(int j=0;j<v[i].size();j++){
int y=v[i][j];
vi[y]=1;
if(vi[y+1]&&y<n){
int xx=fd(y),yy=fd(y+1);
if(xx!=yy)
f[xx]=yy;
}
if(vi[y-1]&&y>1){
int xx=fd(y),yy=fd(y-1);
if(xx!=yy)
f[xx]=yy;
}
}
for(int j=0;j<v[i].size();j++){
int y=v[i][j];
int xx=fd(y);
if(!c[xx]){
st[++tp]=xx;
c[xx]=++ct;
g[y].push_back(c[xx]);
}
else{
g[y].push_back(c[xx]);
}
}
for(int i=1;i<=tp;i++)
c[st[i]]=0;
tp=0;
}
for(int i=1;i<=n;i++){
for(int j=0;j<g[i].size();j++){
int x=g[i][j];
if(la[x])
ad(la[x],-1);
la[x]=i;
ad(i,1);
}
for(int j=0;j<qu[i].size();j++)
ans[qu[i][j].id]=qv(i)-qv(qu[i][j].l-1);
}
for(int i=1;i<=q;i++){
printf("%d
",ans[i]);
}
}