JOIST2025 记录
Rainbow_sjy 更的速度不比我慢多了?
慢慢更。
题解写完了的:D1T3(Travel)D2T2(Stamps)D2T1(Ambulance)D4T2(Migration)
有代码的:D1T3(Travel)D2T2(Stamps)D2T1(Ambulance)D4T2(Migration)
Day1
3.21 12:45~17:45.
打的依托。0+0+100=100。随便拉个普及组选手都比我打的高。
T3 读错成 P3350,写完才发现读错了,重新编了个麻烦做法,写了一年。T2 二进制通信的 16 分没拿到,真奶龙。T1 暴力 19 分没拿到,真奶龙。思考时间:1h+2h+1h。这个 T2 感觉完全可以做更多分。
Travel
Southern_Dynasty 跟我说了重构树做法,和我的貌似本质相同,但是显然更好想也更好写。感觉重构树的题从来没有想出来过。
首先考虑整个过程,第一步一定是走到只保留高度小于 \(t_{a,b}+L+0.5\) 中和 \((a,b)\) 连通的最高点,接下来也是这么走。考虑维护 \(f_{i,j}\) 代表从 \(i\) 出发走 \(j\) 步能到达的最高点是哪个点,有 \(f_{i,j}=f_{f_{i,j-1},j-1}\)。考虑如何判定,即关注 \(f_{(a,b),\infty}\) 能否到达 \((c,d)\)。重构树可以直接做这个东西,不过我是彩笔,在启发式合并的过程中维护了每个询问第一次合并起来的时间,本质和重构树相同。还需要关注 \(f_{i,0}\) 是啥,这也可以在启发式合并的时候维护。
赛时代码,真的依托。
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define pb push_back
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e18,MOD1=998244353,MOD2=1e9+7;
const int maxn=3e5+10;
int qx1[maxn],L,qy1[maxn],qx2[maxn],qy2[maxn],h,w,q,t[maxn],f[maxn][20],s[maxn],nxt[maxn],dx[]={1,-1,0,0},dy[]={0,0,1,-1},sz[maxn],mx[maxn],id[maxn];
vpair vec[maxn];
vint ab[maxn];
struct Info{
int t,x,y;
}a[maxn];
bool cmp(Info s1,Info s2){
return s1.t<s2.t;
}
int go(int x){
if(nxt[x]==x) return x;
return nxt[x]=go(nxt[x]);
}
int to(int x,int y){
return (x-1)*w+y;
}
int my(int x){
return x<0?-x:x;
}
pii ot(int x){
pii res;
res.fi=x/w+1;
if(x%w==0) res.fi--;
res.se=x%w;
if(res.se==0) res.se=w;
return res;
}
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(h),read(w),read(L);
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++) read(t[to(i,j)]),a[to(i,j)].x=i,a[to(i,j)].y=j,a[to(i,j)].t=t[to(i,j)];
read(q);
for(int i=1;i<=q;i++) read(qx1[i]),read(qy1[i]),read(qx2[i]),read(qy2[i]),ab[to(qx1[i],qy1[i])].pb(i),ab[to(qx2[i],qy2[i])].pb(i);
std::sort(a+1,a+h*w+1,cmp);
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++) sz[to(i,j)]=1,nxt[to(i,j)]=to(i,j),vec[to(i,j)].pb({i,j}),f[to(i,j)][0]=to(i,j),mx[to(i,j)]=t[to(i,j)],id[to(i,j)]=to(i,j);
int cid=1;
a[h*w+1].t=inf;
for(int i=1;i<=h*w;i++){
int x=a[i].x,y=a[i].y;
for(int k=0;k<4;k++){
int nx=a[i].x+dx[k],ny=a[i].y+dy[k];
if(nx<1||ny<1||nx>h||ny>w) continue;
if(go(to(x,y))==go(to(nx,ny))) continue;
if(a[i].t<t[to(nx,ny)]) continue;
if(sz[go(to(x,y))]<=sz[go(to(nx,ny))]){
sz[go(to(nx,ny))]+=sz[go(to(x,y))];
int pos=go(to(x,y));
nxt[go(to(x,y))]=go(to(nx,ny));
for(pii j:vec[pos]){
// if(a[i].t<=t[to(j.fi,j.se)]+L){
// if(mx[go(to(nx,ny))]>f[to(j.fi,j.se)][0]) f[to(j.fi,j.se)][0]=id[go(to(nx,ny))];
// }
for(int qu:ab[to(j.fi,j.se)]){
if(s[qu]!=0) continue;
if(go(to(qx1[qu],qy1[qu]))==go(to(qx2[qu],qy2[qu]))) s[qu]=a[i].t;//,debug("qu=%lld x=%lld y=%lld\n",qu,x,y);
}
vec[go(to(nx,ny))].push_back(j);
}
if(chkmax(mx[go(to(nx,ny))],mx[pos])) id[go(to(nx,ny))]=id[pos];
vec[pos].clear();
}else{
sz[go(to(x,y))]+=sz[go(to(nx,ny))];
int pos=go(to(nx,ny));
nxt[go(to(nx,ny))]=go(to(x,y));
for(pii j:vec[pos]){
for(int qu:ab[to(j.fi,j.se)]){
if(s[qu]) continue;
if(go(to(qx1[qu],qy1[qu]))==go(to(qx2[qu],qy2[qu]))) s[qu]=a[i].t;
// vec[go(to(nx,ny))]
}
vec[go(to(x,y))].push_back(j);
}
if(chkmax(mx[go(to(x,y))],mx[pos])) id[go(to(x,y))]=id[pos];
vec[pos].clear();
}
}
while(cid<=h*w&&a[cid].t+L>=a[i].t&&a[cid].t+L<a[i+1].t) f[to(a[cid].x,a[cid].y)][0]=id[go(to(a[cid].x,a[cid].y))]/*,debug("cid=%lld t=%lld %lld %lld %lld\n",cid,a[i].t,a[i+1].t,a[cid].x,a[cid].y)*/,cid++;
}
// for(int i=1;i<=h;i++)
// for(int j=1;j<=w;j++) debug("%lld %lld f=%lld\n",i,j,f[to(i,j)][0]);
// for(int i=1;i<=h;i++)
// for(int j=1;j<=w;j++){
// f[to(i,j)][0]=to(i,j);
// for(int k=0;k<4;k++){
// int nx=i+dx[k],ny=j+dy[k];
// if(nx<1||ny<1||nx>h||ny>w) continue;
// if(my(t[to(i,j)]-t[to(nx,ny)])<L) continue;
// if(t[f[to(i,j)][0]]<t[to(nx,ny)]) f[to(i,j)][0]=to(nx,ny);
// }
// }
for(int j=1;j<20;j++)
for(int i=1;i<=h*w;i++) f[i][j]=f[f[i][j-1]][j-1];
for(int i=1;i<=q;i++){
//answer
// debug("i=%lld s=%lld f=%lld\n",i,s[i],f[to(qx1[i],qy1[i])][19]);
if(!s[i]){
println(-1);
continue;
}
if(t[f[to(qx1[i],qy1[i])][19]]<s[i]){
println(-1);;
continue;
}
// debug("i=%lld s=%lld\n",i,s[i]);
int dis=0,now=to(qx1[i],qy1[i]);
for(int j=19;j>=0;j--){
// debug("now=%lld f=%lld t=%lld\n",now,f[now][j],t[f[now][j]]);
if(t[f[now][j]]>=s[i]) continue;
// debug("now=%lld f=%lld\n",now,f[now][j]);
dis+=(1ll<<j),now=f[now][j];
}
println(dis+1);
}
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
/*
6 5 11
175 100 110 117 158
144 133 123 150 191
167 252 219 181 346
231 241 280 201 209
261 332 325 225 338
269 298 315 291 308
12
1 1 4 2
1 1 1 5
1 1 5 1
1 1 5 4
1 1 3 4
1 1 6 4
1 1 2 5
1 1 3 1
1 1 4 4
1 1 5 5
1 1 6 2
1 1 6 1
*/
Exhibition
目前只会暴力。首先按位确定,这样每个数的限制形如一个区间,可以转化成如下子问题:
给定 \(n\) 个区间,\(i\) 必须要填在 \(a[l_i,r_i]\) 中,问是否可行。
这个可以贪心 \(O(n)\) check。
妈的为啥我这道题看了一天没看明白。
Fortune
看上去比较好玩的通信题,目前有个大概最优能做到 \(20<x\le 100\) 次的做法?总体思路就是类似 3B1B 视频里那样有损压缩加检验码。
等明天有空再写具体思路。
Day2
3.22 忘了。
一如既往奶龙,T3 假了一次,假成神秘 KTT 维护神秘一次函数了??实际上并不难。
Ambulance
很有意思!
四个点还是太多了,考虑进一步减少限制。若只有 \((1,1)\) 和 \((L,L)\) 两个点应该怎么办?让 \(C_i\) 代表 \(i\) 到 \((1,1)\) 的成本,\(D_i\) 代表 \(i\) 到 \((L,L)\) 的成本,此时有 \(C_i+D_i\) 为一个常数。因此我们按照 \(C_i\) 排序后取一个前缀到 \((1,1)\),其余点到 \((L,L)\) 即可。
这样我们有一个 \(O(2^n)\) 的做法。考虑将所有点分别按照 \(cost(1,1)\) 和 \(cost(1,L)\) 排序,这样对于每种分组方案而言,存在两个数 \(b_0\) 和 \(b_1\),使得只有当 \(i\) 按照第一种排序方式后位置 \(\le b_0\) 才能选择 \((1,1)\)(否则不能选择 \((1,1)\),可以选择 \((L,L)\)),按照第二种排序方式后位置 \(\le b_1\) 才能选择 \((1,L)\)(否则不能选择 \((1,L)\),可以选择 \((L,1)\))。这样如果我们确定了 \(b_0\) 和 \(b_1\),那么所有点会被分成四组,每组存在两个选择。
接下来对于每组分别 dp。\(f_i\) 代表当该组的第一个选择耗时 \(i\) 时第二个选择的最小耗时。这个 dp 的总时间复杂度时 \(O(nT)\) 的。对于四组的 dp 全都做完以后,考虑在第一组(两个选择分别为 \((1,1)\) 和 \((1,L)\))钦定 \((1,1)\) 的耗时,这样能得到 \((1,L)\) 的剩余时间,接着在剩下三组中贪心即可。由于需要枚举 \(b_0\) 和 \(b_1\),时间复杂度为 \(O(n^3T)\)。无法通过。
实际上我们移动 \(b_0\) 和 \(b_1\) 的增量只有 \(1\),这意味着每次移动只会带来 \(O(1)\) 个点更换组别,我们维护前缀 dp 值和后缀 dp 值可以简单做到 \(O(n^2T)\)。
真卡不动了,卡常好玩吗?
#include<bits/stdc++.h>
// #define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e9,MOD1=998244353,MOD2=1e9+7;
const int maxn=210,maxT=2e4+10;
int l,n,t,x[maxn],y[maxn],f[4][maxn][maxT],g[4][maxn][maxT],in[2][maxn],ok[4][maxn],cnt[4],mi[4][maxT];
pii a[maxn],b[maxn],cho[4],choo[4];
//ok[0]:dp:(1,1) (1,L) insert b[b1].se
//ok[1]:(1,1) dp:(L,1) erase b[b1-1].se
//ok[2]:(L,L) dp:(1,L) insert b[b1].se
//ok[3]:dp:(L,L) (L,1) erase b[b1].se
int my(int x){
return x<0?-x:x;
}
int cost(int id,int X,int Y){
return my(x[id]-X)+my(y[id]-Y);
}
int cost(int id,pii c){
return my(x[id]-c.fi)+my(y[id]-c.se);
}
void getans(int*f1,int*f2,int*f3,int*f4){
mi[0][0]=f1[0],mi[1][0]=f2[0],mi[2][0]=f3[0],mi[3][0]=f4[0];
for(int i=1;i<=t;i++){
mi[0][i]=std::min(mi[0][i-1],f1[i]);
mi[1][i]=std::min(mi[1][i-1],f2[i]);
mi[2][i]=std::min(mi[2][i-1],f3[i]);
mi[3][i]=std::min(mi[3][i-1],f4[i]);
}
for(int i=0;i<=t;i++){
if(f1[i]>t) continue;
int les=t-f1[i];
les=mi[2][les];
if(les>t) continue;
les=t-les;
les=mi[3][les];
if(les>t) continue;
les=t-les;
les=mi[1][les];
if(les+i>t) continue;
printf("Yes\n");
exit(0);
}
}
bool cmp(int s1,int s2){
return in[1][s1]<in[1][s2];
}
#define rev(a,sz) std::reverse(a+1,a+sz+1)
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(l),read(n),read(t);
for(int i=1;i<=n;i++) read(x[i]),read(y[i]),a[i]={cost(i,1,1),i},b[i]={cost(i,1,l),i};
std::sort(a+1,a+n+1),std::sort(b+1,b+n+1);
for(int i=1;i<=n;i++) in[0][a[i].se]=i,in[1][b[i].se]=i;
cho[0]={1,1},choo[0]={1,l};
cho[1]={1,1},choo[1]={l,1};
cho[2]={l,l},choo[2]={1,l};
cho[3]={l,l},choo[3]={l,1};
std::swap(cho[1],choo[1]),std::swap(cho[2],choo[2]);
for(int b0=0;b0<=n;b0++){
int b1=0;
for(int i=0;i<4;i++) cnt[i]=0;
for(int i=1;i<=n;i++){
int s=0;
if(in[0][i]>b0) s+=2;
if(in[1][i]>b1) s++;
ok[s][++cnt[s]]=i;
}
std::sort(ok[1]+1,ok[1]+cnt[1]+1,cmp),std::sort(ok[3]+1,ok[3]+cnt[3]+1,cmp);
rev(ok[1],cnt[1]),rev(ok[3],cnt[3]);
for(int i=0;i<4;i++){
f[0][0][0]=0;
for(int k=1;k<=t;k++) f[i][0][k]=inf;
for(int j=1;j<=cnt[i];j++)
for(int k=0;k<=t;k++){
f[i][j][k]=f[i][j-1][k]+cost(ok[i][j],choo[i])*2;
if(k>=cost(ok[i][j],cho[i])*2) chkmin(f[i][j][k],f[i][j-1][k-cost(ok[i][j],cho[i])*2]);
}
}
getans(f[0][cnt[0]],f[1][cnt[1]],f[2][cnt[2]],f[3][cnt[3]]);
b1++;
for(;b1<=n;b1++){
if(in[0][b[b1].se]<=b0) cnt[1]--;
else cnt[3]--;
bool f1=0,f2=0;
if(in[0][b[b1].se]<=b0) ok[0][++cnt[0]]=b[b1].se,f1=1;
else ok[2][++cnt[2]]=b[b1].se,f2=1;
for(int j=0;j<=2;j+=2)
for(int k=0;k<=t;k++){
if(cnt[j]==0) break;
if(j==0&&(!f1)) break;
if(j==2&&(!f2)) break;
f[j][cnt[j]][k]=f[j][cnt[j]-1][k]+cost(ok[j][cnt[j]],choo[j])*2;
if(k>=cost(ok[j][cnt[j]],cho[j])*2) chkmin(f[j][cnt[j]][k],f[j][cnt[j]-1][k-cost(ok[j][cnt[j]],cho[j])*2]);
}
getans(f[0][cnt[0]],f[1][cnt[1]],f[2][cnt[2]],f[3][cnt[3]]);
}
}
printf("No\n");
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
/*
7 7 16
6 1
2 4
4 5
5 5
3 4
6 4
5 1
200 15 800
126 45
196 40
43 58
96 13
28 33
44 55
60 22
58 156
135 183
44 29
92 182
157 138
30 132
175 87
166 57
*/
Thief
Stamps
观察到若我们钦定了起点,则能得到的邮票数可以比较容易地刻画。若两个 \(a\) 都出现在两个 \(b\) 之前,那我们一定无法得到 \(ba\),因此得到的邮票数就是总数 \(n^2\) 减去这样的 \(ab\) 数量。考虑修改操作,有结论:每次修改一定都能减少恰好一对 \(ab\)(称之为坏的数对)。
这个结论直观上就很对,不过还是给出证明。考虑存在上文中的 \(ab\) 满足四个数位置分别是 \(a_1<a_2<b_1<b_2\),则此时有两种情况,交换 \(b_1\) 和 \(b_1-1\) 会减少或不会减少一对坏的数对。减少则证毕,否则设 \(b_1-1\) 的颜色是 \(c\),则一定有 \(ac\) 是一对坏的数对,归纳下去即可。
这样对于每个起点,可以求出其初始能得到多少邮票,记作\(D_i\),若询问的 \(K_q\) 大于 \(D_i\),此时代价就为 \(C_i+(K_q-D_i)X\),否则为 \(C_i\),这个问题可以简单扫描线解决。至于如何求出 \(D_i\)?同样可以扫描线。
开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。开 i128。
同样依托
#include<bits/stdc++.h>
#define int __int128
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e30,MOD1=998244353,MOD2=1e9+7;
const int maxn=1e6+10;
int n,x,a[maxn],c[maxn],q,k[maxn],s[maxn],d[maxn],p1[maxn],p2[maxn],ans[maxn],mi[maxn];
int lowbit(int x){
return x&(-x);
}
struct BIT{
int s[maxn];
void upd(int pos,int k){
for(;pos<=2*n;pos+=lowbit(pos)) s[pos]+=k;
}
int query(int pos){
if(pos<0) return 0;
if(pos>2*n) return 0;
int res=0;
while(pos) res+=s[pos],pos-=lowbit(pos);
return res;
}
int qry(int l,int r){
if(l>r) return query(2*n)-query(l-1)+query(r);
return query(r)-query(l-1);
}
}ds,ds2;
pii ask[maxn],sta[maxn];
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(n),read(x);
for(int i=1;i<=n*2;i++) read(a[i]);
for(int i=1;i<=2*n;i++) read(c[i]);
for(int i=1;i<=2*n;i++){
if(!p1[a[i]]) p1[a[i]]=i;
else p2[a[i]]=i;
}
for(int i=1;i<=2*n;i++){
if(i==p2[a[i]]) ds.upd(i,1);//,debug("i=%lld\n",i);
else d[1]+=ds.qry(1,i),ds2.upd(i,1);
}
// debug("d1=%lld\n",d[1]);
for(int i=2;i<=2*n;i++){
//删去 i-1 的贡献
if(p1[a[i-1]]!=i-1) std::swap(p1[a[i-1]],p2[a[i-1]]);
d[i]=d[i-1];
if(p2[a[i-1]]+1!=i-1)d[i]-=ds2.qry(p2[a[i-1]]+1,i-2);
// debug("d=%lld p2=%lld\n",d[i],p2[a[i-1]]);
//加上 i-1 的贡献
ds.upd(p2[a[i-1]],-1),ds.upd(p1[a[i-1]],1);
if(p2[a[i-1]]!=i) d[i]+=ds.qry(i,p2[a[i-1]]-1);
ds2.upd(p1[a[i-1]],-1),ds2.upd(p2[a[i-1]],1);
std::swap(p1[a[i-1]],p2[a[i-1]]);
// debug("i=%lld d=%lld\n",i,d[i]);
}
for(int i=1;i<=2*n;i++) sta[i]={n*n-d[i],i};
std::sort(sta+1,sta+2*n+1);
mi[2*n+1]=inf;
for(int i=2*n;i>=1;i--) mi[i]=std::min(mi[i+1],c[sta[i].se]);
int z=1,cost=inf;
read(q);
for(int i=1;i<=q;i++) read(ask[i].fi),ask[i].se=i;
std::sort(ask+1,ask+q+1);
for(int i=1;i<=q;i++){
while(z<=2*n&&sta[z].fi<ask[i].fi) chkmin(cost,c[sta[z].se]-sta[z].fi*x),z++;
ans[ask[i].se]=std::min(mi[z],cost+ask[i].fi*x);
}
for(int i=1;i<=q;i++) println(ans[i]);
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
Day3
Brave
Conference
Multi
Output only task.
存在简单的构造策略做到 \(O(\log^2 n)\)。
Day4
Circuit
Migration
我草,我悟道了!很牛啊这题。
首先给一个 \(2\log\) 的做法。我们对于每个深度维护一个 set,代表点和点权,如果没有点权就不加进去。操作一启发式合并,同时及时合并同一个点的点权;操作二加进去一个新点合并;操作三 set 上二分。总时间复杂度 \(O((n+q)\log^2(n+q))\)。
考虑优化。把启发式合并变成线段树合并。具体来说,依然是每个深度维护一棵线段树,线段树的下标为 dfs 序,下标维护的权值是对应点的点权。遇到操作一直接线段树合并,注意此时一个点的点权可能会被拆成线段树上很多个点的的点权,不过这没关系。操作二插入即可。操作三查询该点对应子树在对应深度线段树上的权值之和!时间复杂度 \(O((n+q)\log(n+q))\)。
线段树合并时根本不需要加上可持久化!因为即使有修改,也不会影响到儿子的求值!同时对于操作一需要清空的深度,直接重置根节点即可!
并非依托
#include<bits/stdc++.h>
// #define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)
template<typename T>
void read(T &x){
x=0;
int f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
x*=f;
}
std::stack<char>st;
template<typename T>
void print(T x){
if(x==0) putchar('0');
if(x<0) putchar('-'),x=-x;
while(st.size()) st.pop();
while(x) st.push((char)('0'+x%10)),x/=10;
while(st.size()) putchar(st.top()),st.pop();
}
template<typename T>
void printsp(T x){
print(x),putchar(' ');
}
template<typename T>
void println(T x){
print(x),putchar('\n');
}
template<typename T,typename I>
bool chkmin(T &a,I b){
if(a>b) return a=b,1;
return 0;
}
template<typename T,typename I>
bool chkmax(T &a,I b){
if(a<b) return a=b,1;
return 0;
}
template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
vec[u].push_back(v);
}
template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
vec[u].push_back({v,w});
}
template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
addedge(vec,u,v),addedge(vec,v,u);
}
template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
addedge(vec,u,v,w),addedge(vec,v,u,w);
}
bool Mbe;
const int inf=1e9,MOD1=998244353,MOD2=1e9+7;
const int maxn=2e6+10;
int n,q,fa[maxn],din[maxn],dout[maxn],rt[maxn],cnt,dep[maxn];
vint a[maxn];
struct SegmentTree{
int ls[maxn*40],rs[maxn*40],sum[maxn*40];
int tot=0;
void clear(){
tot=0;
}
void push_up(int p){
sum[p]=sum[ls[p]]+sum[rs[p]];
}
void update(int &rt,int l,int r,int pos,int k){
if(!rt) rt=++tot;
if(l==r){
sum[rt]+=k;
return ;
}
int mid=(l+r)>>1;
if(mid>=pos) update(ls[rt],l,mid,pos,k);
else update(rs[rt],mid+1,r,pos,k);
push_up(rt);
}
void merge(int &p1,int &p2,int l,int r){
if(!p2) return ;
if(!p1){
p1=p2;
return ;
}
if(l==r){
sum[p1]+=sum[p2];
return ;
}
int mid=(l+r)>>1;
merge(ls[p1],ls[p2],l,mid),merge(rs[p1],rs[p2],mid+1,r);
push_up(p1);
}
int query(int rt,int l,int r,int L,int R){
if(!rt) return 0;
if(l>=L&&r<=R) return sum[rt];
int mid=(l+r)>>1,res=0;
if(mid>=L) res+=query(ls[rt],l,mid,L,R);
if(R>mid) res+=query(rs[rt],mid+1,r,L,R);
return res;
}
}ds;
void dfs(int p){
din[p]=++cnt;
// dep[p]=dep[fa[p]]+1;
for(int i:a[p]){
if(i==fa[p]) continue;
dep[i]=dep[p]+1;
dfs(i);
}
dout[p]=cnt;
}
bool Men;
signed main(){
debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
read(n);//,read(q);
for(int i=2;i<=n;i++) read(fa[i]),addd(a,i,fa[i]);
dfs(1);
for(int i=1;i<=n;i++){
int val;
read(val);
ds.update(rt[dep[i]],1,n,din[i],val);
}
read(q);
while(q--){
int opt,x;
read(opt),read(x);
if(opt==1){
int y;
read(y);
ds.merge(rt[y],rt[x],1,n);
rt[x]=0;
continue;
}
if(opt==2){
int l;
read(l);
ds.update(rt[dep[x]],1,n,din[x],l);
}
if(opt==3) println(ds.query(rt[dep[x]],1,n,din[x],dout[x]));
}
debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}