A - CF538G Berserk Robot
Sol
将原题中的坐标 ( x , y ) (x,y) (x,y)变成 ( x + y , x − y ) (x+y,x-y) (x+y,x−y),原题的行走一步改成 ( 1 , 1 ) , ( 1 , − 1 ) , ( − 1 , 1 ) , ( − 1 , − 1 ) (1,1),(1,-1),(-1,1),(-1,-1) (1,1),(1,−1),(−1,1),(−1,−1)。这样与原来的问题是等价的,并且横纵坐标变得独立了。
单独对每一维考虑。设走完这 l l l步坐标的变化量为 d x dx dx。
如果有两个 t i t_i ti模 l l l的余数相同,就可以解出 d x dx dx,然后进行构造。
否则将已知的点将 t i m o d l t_i \bmod l timodl排序,相邻的两个算一下它们对 d x dx dx的限制。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#define db long double
#define PB push_back
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=getchar();}
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
int curtest;
void FAIL() { printf("NO"); exit(0); }
ll Abs(ll x) { return x>0?x:-x; }
db eps=1e-20;
int dcmp(db x) { return x>-eps?(x>eps):-1; }
const int N=2e6+10;
vector<int> pos;
struct node { ll t,x,y; }v[N];
ll val[N],ti[N];
int vis[N];
int m,n;
db lb,rb;
vector<char> S;
void modify(int p,ll x,ll delt) {
if(Abs((delt*m+p)%2)^Abs(x%2)) FAIL();
if(delt==0) return;
ll l=-p-x,r=p-x; db dt=-delt;
if(dt>0) lb=max(lb,l/dt),rb=min(rb,r/dt);
else lb=max(lb,r/dt),rb=min(rb,l/dt);
}
void sol(vector<int> &ans) {
lb=-m,rb=m;
for(int i=0;i+1<pos.size();++i) {
if(i+2==pos.size()) modify(m-pos[i],-val[pos[i]],-ti[pos[i]]-1);
else modify(pos[i+1]-pos[i],val[pos[i+1]]-val[pos[i]],ti[pos[i+1]]-ti[pos[i]]);
}
ll dx=floor(rb);
if(Abs(dx%2)^(m%2)) dx--;
if(dcmp(dx-lb)<0) FAIL();
for(int i=0;i+1<pos.size();++i) {
int l=pos[i],r=pos[i+1],len=r-l;
ll x=(r==m?dx:val[r])-val[l]-(ti[r]-ti[l])*dx;
int d=x>0?1:-1;
x=Abs(x); len-=x;
while(x) x--,ans.PB(d);
if(len<0||(len&1)) FAIL();
while(len) ans.PB(1),ans.PB(-1),len-=2;
}
}
ll dx,dy;
void solve(int l,int r,ll x,ll y,ll t) {
x-=t*dx,y-=t*dy;
char xx=x>0?'R':'L';
char yy=y>0?'U':'D';
x=Abs(x),y=Abs(y);
while(x--) S.PB(xx),r--;
while(y--) S.PB(yy),r--;
if(((r-l)&1)||r-l<0) FAIL();
while(r-l) S.PB('U'),S.PB('D'),r-=2;
}
vector<int> ax,ay;
int main() {
rd(n),rd(m);
int flg=0;
vis[0]=1,v[0].x=v[0].y=v[0].t=0;
for(int i=1;i<=n;++i) {
node A;
rd(A.t),rd(A.x),rd(A.y);
int p=A.t%m;
A.t/=m;
if(vis[p]) {
if(A.t==v[p].t) {
if(A.x!=v[p].x||A.y!=v[p].y) FAIL();
continue;
}
ll dt=A.t-v[p].t;
if(flg) {
if(v[p].x+dt*dx==A.x&&v[p].y+dt*dy==A.y) continue;
else FAIL();
}
dx=A.x-v[p].x,dy=A.y-v[p].y;
if(dx%dt||dy%dt) FAIL();
dx/=dt,dy/=dt;
flg=1;
}
else v[p]=A,vis[p]=1;
}
if(flg) {
int p1=0,p2;
while(true) {
p2=p1+1;
while(!vis[p2]&&p2<m) p2++;
if(p2>=m) break;
solve(p1,p2,v[p2].x-v[p1].x,v[p2].y-v[p1].y,v[p2].t-v[p1].t);
p1=p2;
}
solve(p1,m,dx-v[p1].x,dy-v[p1].y,-v[p1].t);
for(int i=0;i<S.size();++i) putchar(S[i]);
}
else {
for(int i=0;i<m;++i) if(vis[i]) ti[i]=v[i].t,pos.PB(i);
pos.PB(m),ti[m]=0;
for(int i=0;i<m;++i) if(vis[i]) val[i]=v[i].x+v[i].y;
sol(ax);
for(int i=0;i<m;++i) if(vis[i]) val[i]=v[i].x-v[i].y;
sol(ay);
for(int i=0;i<m;++i) {
if(ax[i]==ay[i]) putchar(ax[i]>0?'R':'L');
else putchar(ax[i]>0?'U':'D');
}
}
return 0;
}
B - CF674D Bearish Fanpages
Sol
对每个点维护它的所有儿子对它的贡献的和,这样可以在 O ( 1 ) O(1) O(1)的时间完成修改,在 O ( 1 ) O(1) O(1)的时间完成对某个点价值的查询。
维护全局最大最小值:对每个点 x x x维护一个multiset,里面存所有儿子的(这个儿子的价值- x x x对儿子的贡献),然后将multiset中的最大的和最小的加上 x x x的贡献放入一个全局的multiset。这样修改操作jiang可以在 O ( log n ) O(\log n) O(logn)的时间内完成。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=getchar();}
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
const int N=1e5+10;
int du[N],fa[N],n;
ll ans[N],ti[N];
multiset<ll> s[N],que;
int tim,vis[N];
inline ll cot(int x) { return ti[x]/(du[x]+1); }
inline ll get(int x) { return ans[x]+(ti[x]-cot(x)*du[x]); }
inline ll getans(int x) { return cot(fa[x])+get(x); }
void Ins(int x) { if(vis[x]==tim) return; vis[x]=tim; if(!s[x].empty()) que.insert(cot(x)+(*s[x].rbegin())),que.insert(cot(x)+(*s[x].begin())); }
void Del(int x) { if(vis[x]==tim) return; vis[x]=tim; if(!s[x].empty()) que.erase(que.find(cot(x)+(*s[x].rbegin()))),que.erase(que.find((cot(x)+(*s[x].begin())))); }
void link(int x,int f) {
int ff=fa[f];
tim++,Del(x),Del(f),Del(ff),Del(fa[ff]);
if(ff) {
if(fa[ff]) s[fa[ff]].erase(s[fa[ff]].find(get(ff)));
s[ff].erase(s[ff].find(get(f)));
ans[ff]-=cot(f);
}
fa[x]=f,du[x]++,du[f]++;
ans[f]+=cot(x);
s[f].insert(get(x));
if(ff) {
ans[ff]+=cot(f);
s[ff].insert(get(f));
if(fa[ff]) s[fa[ff]].insert(get(ff));
}
tim++,Ins(x),Ins(f),Ins(ff),Ins(fa[ff]);
}
void cut(int x) {
int f=fa[x],ff=fa[f];
tim++,Del(x),Del(f),Del(ff),Del(fa[ff]);
if(ff) {
if(fa[ff]) s[fa[ff]].erase(s[fa[ff]].find(get(ff)));
s[ff].erase(s[ff].find(get(f)));
ans[ff]-=cot(f);
}
s[f].erase(s[f].find(get(x)));
ans[f]-=cot(x);
du[x]--,du[fa[x]]--,fa[x]=0;
if(ff) {
ans[ff]+=cot(f);
s[ff].insert(get(f));
if(fa[ff]) s[fa[ff]].insert(get(ff));
}
tim++,Ins(x),Ins(f),Ins(ff),Ins(fa[ff]);
}
int main() {
int q; rd(n),rd(q);
for(int i=1;i<=n;++i) rd(ti[i]);
for(int f,i=1;i<=n;++i) rd(f),link(i,f);
while(q--) {
int ty,x,y; rd(ty);
if(ty==1) {
rd(x),rd(y);
cut(x);
link(x,y);
}
else if(ty==2) rd(x),printf("%lld\n",getans(x));
else printf("%lld %lld\n",*que.begin(),*que.rbegin());
}
return 0;
}
C - ARC101F Robots and Exits
Sol
对于每个机器人,显然它最终对应的出口只可能是它左边的第一个或者右边的第一个。假设机器人 i i i对应的两个出口到机器人 i i i的坐标变化量分别为 l i , r i l_i,r_i li,ri,其中 l i < 0 , r i > 0 l_i < 0, r_i > 0 li<0,ri>0。
考虑机器人们的坐标相对于最初的坐标的变化量关于时间变化的函数,则对于每个机器人来说,它会从哪个口出去,只与这个函数与 y = l i y=l_i y=li和 y = r i y=r_i y=ri的第一个交点哪一个横坐标更小有关。
观察发现可能的方案数就是将所有的机器人按照 l i l_i li从小到大排序( l i l_i li相同则 r i r_i ri大的放在前面)之后, r i r_i ri所能够形成的上升子序列的数量。
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
template <class T>
inline void rd(T &x) {
x=0; char c=getchar(); int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=getchar();}
while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;
}
const int N=1e5+10,mod=1e9+7;
struct node {
int x,y;
node(int x=0,int y=0): x(x),y(y) {}
friend bool operator <(node A,node B) { return A.x==B.x?A.y>B.y:A.x>B.x; }
friend bool operator ==(node A,node B) { return A.x==B.x&&A.y==B.y; }
}a[N];
int xi[N],yi[N],n,m,cnt;
int val[N],tot;
int c[N];
void add(int i,int t) { for(;i<=tot;i+=i&-i) c[i]=(c[i]+t)%mod; }
int query(int i) { int ans=0; for(;i;i-=i&-i) ans=(ans+c[i])%mod; return ans; }
int main() {
rd(n),rd(m);
for(int i=1;i<=n;++i) rd(yi[i]);
for(int i=1;i<=m;++i) rd(xi[i]);
for(int i=1;i<=n;++i) {
if(yi[i]<=xi[1]||yi[i]>=xi[m]) continue;
int r=lower_bound(xi+1,xi+m+1,yi[i])-xi;
int l=r-1;
a[++cnt]=node(xi[l]-yi[i],xi[r]-yi[i]);
}
sort(a+1,a+cnt+1);
cnt=unique(a+1,a+cnt+1)-a-1;
for(int i=1;i<=cnt;++i) val[++tot]=a[i].y;
sort(val+1,val+tot+1);
tot=unique(val+1,val+tot+1)-val-1;
for(int i=1;i<=cnt;++i) a[i].y=lower_bound(val+1,val+tot+1,a[i].y)-val;
int ans=1;
for(int i=1;i<=cnt;++i) {
int t=(query(a[i].y-1)+1)%mod;
ans=(ans+t)%mod;
add(a[i].y,t);
}
printf("%d",ans);
return 0;
}
[i].y;
sort(val+1,val+tot+1);
tot=unique(val+1,val+tot+1)-val-1;
for(int i=1;i<=cnt;++i) a[i].y=lower_bound(val+1,val+tot+1,a[i].y)-val;
int ans=1;
for(int i=1;i<=cnt;++i) {
int t=(query(a[i].y-1)+1)%mod;
ans=(ans+t)%mod;
add(a[i].y,t);
}
printf("%d",ans);
return 0;
}