POI 2022 Stage I
Kolorowy w?? (kol)
用棧從蛇尾到蛇頭記錄每一段身體的顏色,每次蛇頭變化都認為是新長出了一個蛇頭。
對于每個坐標,記錄它最后一次是被哪個蛇頭經(jīng)過的,那么根據(jù)蛇頭版本的差值可以得到對應蛇身相對于蛇頭的名次,然后即可在棧中找到對應的顏色。
每次操作的時間復雜度為$O(1)$。
#include<cstdio>
const int N=2005;
int n,m,q,i,j,x,y,z,cnt,len,col[N*N],bean[N][N],last[N][N];char op[9];
inline int ask(int x,int y){
if(x<1||x>n||y<1||y>n)return -1;
int o=last[x][y];
if(!o)return -1;
o=cnt-o+1;
if(o>len)return -1;
return col[len-o+1];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
while(m--)scanf("%d%d%d",&i,&j,&z),bean[i][j]=z+1;
x=y=cnt=len=last[1][1]=1;
while(q--){
scanf("%s",op);
if(op[0]=='Z'){
scanf("%d%d",&i,&j);
printf("%d\n",ask(i,j));
continue;
}
if(op[0]=='G')x--;
else if(op[0]=='D')x++;
else if(op[0]=='L')y--;
else y++;
if(bean[x][y]){
col[++len]=bean[x][y]-1;
bean[x][y]=0;
}
last[x][y]=++cnt;
}
}
P?ytkie nawiasowania (ply)
將 '(' 視為$1$,')' 視為$-1$,那么需要滿足前綴和介于$[0,k]$,且總和為$0$。
從左往右模擬,一旦在當前位置發(fā)現(xiàn)前綴和不在$[0,k]$,就反轉當前的括號,一定可以保證代價最小。
時間復雜度$O(n)$。
#include<cstdio>
const int N=1000005;
int n,k,i,s,ans;char a[N];
int main(){
scanf("%d%d%s",&n,&k,a+1);
for(i=1;i<=n;i++){
if(a[i]=='('){
s++;
if(s>k)s-=2,ans++;
}else{
s--;
if(s<0)s+=2,ans++;
}
}
printf("%d",ans);
}
Poci?g towarowy (poc)
找到$pre[i]$表示從左往右貪心匹配出$b[i]$的位置,以及$suf[i]$表示從右往左貪心匹配出$b[i]$的位置。
那么$[pre[i],suf[i]]$中所有值為$b[i]$的位置都可能被匹配,對于$b[i]$這個值出現(xiàn)的所有下標通過差分前綴和打標記即可。
時間復雜度$O(n+m)$。
#include<cstdio>
const int N=300005;
int n,m,k,i,j,a[N],b[N],add[N],del[N],sum[N];
int main(){
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=m;i++)scanf("%d",&b[i]);
for(i=j=1;i<=m;i++){
while(a[j]!=b[i])j++;
add[j++]++;
}
for(i=m,j=n;i;i--){
while(a[j]!=b[i])j--;
del[j--]++;
}
for(i=1;i<=n;i++){
j=a[i];
sum[j]+=add[i];
printf("%d%c",!!sum[j],i<n?' ':'\n');
sum[j]-=del[i];
}
}
Wyprzedzanie (wyp)
相鄰兩輛車一旦緊靠在一起,它們將永遠緊靠在一起,可以合并為一輛車。
提取相鄰兩輛車合并為一個整體的時間點,然后按時間順序模擬即可,使用鏈表+堆維護。
實現(xiàn)的時候,需要使用全整數(shù)分數(shù)類以避免精度誤差。
時間復雜度$O(n\log n)$。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef __int128 lll;
typedef pair<int,int>P;
const int N=100005;
int n,i,j,state,pre[N],nxt[N],del[N],ans;
struct Frac{
ll u,d;
Frac(){}
Frac(ll _u,ll _d){u=_u,d=_d;}
void read(){scanf("%lld%lld",&u,&d);}
int sgn(const Frac&b)const{
lll tmp=((lll)u)*((lll)b.d)-((lll)d)*((lll)b.u);
if(!tmp)return 0;
return tmp>0?1:-1;
}
bool operator<(const Frac&b)const{return sgn(b)<0;}
bool operator<=(const Frac&b)const{return sgn(b)<=0;}
}last;
struct Car{
int x,d;
Frac v;
void read(){scanf("%d%d",&x,&d);v.read();}
}car[N];
typedef pair<Frac,P>E;
priority_queue<E,vector<E>,greater<E> >q;
inline void mergeevent(int A,int B){
if(car[A].v<=car[B].v)return;
int delta=car[B].x-car[B].d-car[A].x;
ll u=1LL*delta*car[A].v.d*car[B].v.d,d=car[A].v.u*car[B].v.d-car[A].v.d*car[B].v.u;
q.push(E(Frac(u,d),P(A,B)));
}
inline Frac cal(int B,int o){
if(del[B])return Frac(-1,-1);
int delta=car[B].x;
if(o==0)delta-=car[B].d;else delta+=car[0].d;
ll u=1LL*delta*car[0].v.d*car[B].v.d,d=car[0].v.u*car[B].v.d-car[0].v.d*car[B].v.u;
return Frac(u,d);
}
int main(){
scanf("%d%d",&n,&car[0].d);
car[0].v.read();
for(i=1;i<=n;i++)car[i].read();
for(i=0;i<=n+1;i++){
pre[i]=i-1;
nxt[i]=i+1;
}
for(i=1;i<n;i++)mergeevent(i,i+1);
last=Frac(0,1);
state=1;
for(i=1;i<=n;i++)for(j=0;j<2;j++){
Frac t=cal(i,j);
while(!q.empty()&&t.u>=0){
E e=q.top();
int A=e.second.first,B=e.second.second;
if(del[B]){
q.pop();
continue;
}
if(t<=e.first)break;
last=e.first;
q.pop();
car[B].d+=car[A].d;
del[A]=1;
t=cal(i,j);
int C=pre[A];
pre[B]=C;
nxt[C]=B;
if(C)mergeevent(C,B);
}
if(t.u<0)continue;
if(t<last)continue;
last=t;
if(j==0){
if(state==1)ans++,state=0;
}else{
if(i<n&&cal(nxt[i],0)<t)continue;
state=1;
}
}
printf("%d",ans);
}
Zbo?e (zbo)
動態(tài)點分治。時間復雜度$O(n\log n)$。
#include<cstdio>
typedef long long ll;
const int N=100005,M=2000005;
int n,k,i,x,y,z;
int g[N],v[N<<1],w[N<<1],nxt[N<<1],ok[N<<1],ed;
int son[N],f[N],all,now,cnt;
int G[N],V[2][M],W[M],NXT[M],ED;
int s[N],se[N];ll sd[N],sed[N],ans;
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;ok[ed]=1;}
inline void ADD(int x,int y,int z,int w){V[0][++ED]=y;V[1][ED]=z;W[ED]=w;NXT[ED]=G[x];G[x]=ED;}
void findroot(int x,int y){
son[x]=1;f[x]=0;
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y){
findroot(v[i],x);
son[x]+=son[v[i]];
if(son[v[i]]>f[x])f[x]=son[v[i]];
}
if(all-son[x]>f[x])f[x]=all-son[x];
if(f[x]<f[now])now=x;
}
void dfs(int x,int y,int dis){
ADD(x,now,cnt,dis);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)dfs(v[i],x,dis+w[i]);
}
void solve(int x){
int i;
for(i=g[x];i;i=nxt[i])if(ok[i])cnt++,dfs(v[i],x,w[i]);
for(i=g[x];i;i=nxt[i])if(ok[i]){
ok[i^1]=0;
f[0]=all=son[v[i]];
findroot(v[i],now=0);
solve(now);
}
}
inline void modify(int x){
ans+=sd[x];
s[x]++;
for(int i=G[x];i;i=NXT[i]){
int A=V[0][i],B=V[1][i],C=W[i];
ans+=sd[A]-sed[B]+1LL*C*(s[A]-se[B]);
s[A]++,sd[A]+=C;
se[B]++,sed[B]+=C;
}
}
int main(){
scanf("%d%d",&n,&k);
for(ed=i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
f[0]=all=n;
findroot(1,0);
solve(now);
modify(1);
while(k--)scanf("%d",&x),modify(x),printf("%lld\n",ans*2);
}

浙公網(wǎng)安備 33010602011771號