#15
Timofey and Black-White Tree
对于新增一个黑点,爆搜将其它所有点到黑点的距离都更新,如果遇到距离更小的或者当前的距离大于答案就不更新了。正确性显然,前者再往下搜肯定不如距离当前点的更小的那个点更新是优秀;后者对答案显然没有影响,因为再搜下去距离会更大。复杂度为 \(O(n\sqrt n)\),复杂度证明可以看 World_Creater的题解。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,m,c[N],dis[N],ans;
vector<int>e[N];
void bfs(int x){
queue<int>q;
q.push(x);
dis[x]=0;
while(q.size()){
int u=q.front();
if(dis[u]>=ans){
return;
}
q.pop();
for(auto v:e[u]){
if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
q.push(v);
}
}
}
}
void solve(){
read(n);
ans=inf;
for(int i=1;i<=n;i++){
read(c[i]);
dis[i]=inf;
e[i].clear();
}
for(int i=1;i<n;i++){
int u,v;
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
bfs(c[1]);
for(int i=2;i<=n;i++){
ans=min(ans,dis[c[i]]);
write_space(ans);
bfs(c[i]);
}
putchar('\n');
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
Arpa’s overnight party and Mehrdad’s silent entering
在 \(a_i\) 和 \(b_i\) 间连一条边,限制 \(a_i\) 和 \(b_i\) 的颜色不同。由于第二个限制,所以可以对于 \(i\in [1,2n)\),限制 \(i\) 和 \(i+1\) 颜色不同。如果图是二分图,说明可行,否则不行。每个点的颜色就是二分图染色的颜色。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=4e5+10;
int n,a[N],b[N],col[N];
vector<int>e[N];
void dfs(int u,int c){
col[u]=c;
for(auto v:e[u]){
if(!col[v]){
dfs(v,3-c);
}
if(col[v]!=3-c){
write_endl(-1);
exit(0);
}
}
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]),read(b[i]);
e[a[i]].pb(b[i]);
e[b[i]].pb(a[i]);
e[i*2].pb(i*2-1);
e[i*2-1].pb(i*2);
}
for(int i=1;i<=n*2;i++){
if(!col[i]){
dfs(i,1);
}
}
for(int i=1;i<=n;i++){
write_space(col[a[i]]),write_endl(col[b[i]]);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Yet Another DAG Problem
之前做了一个赋点权的题,不记得是哪道了,是用网络流做的,这题自然而然地就往网络流上想了。
先给出一个结论,\(a_i\) 是连续的。如果存在一个 \(k\) 满足存在 \(a_i>k,k>a_j\) 且不存在 \(a_p=k\),可以令大于 \(k\) 的 \(a_i\rightarrow a_{i}-1\),这样 \(b_i\) 可以保证不增。`
将贡献 \(w\times(a_u-a_v)\) 拆开,拆成 \(w\times a_u-w\times a_v\),将 \(u\) 贡献增加 \(w\),将 \(v\) 贡献减少 \(w\)。建 \(n\) 条链,令 \((i,j)\) 表示 \(a_i\) 的权值为 \(j\),如果割掉第 \(j\) 条边,则说明权值选 \(j\)。为了保证 \(a_u>a_v\),可以对于 \(j\in[0,n)\),连一条 \((v,j)\rightarrow(u,j+1)\),权值为 \(+\infty\) 的边。最后从 \(S\) 开始跑残量网络,跑到的权值最大的点就是该点的答案。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e18;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=510,M=5e5+10;
int S,T,head[N],tot=1;
int n,m;
struct edge{
int v,w,nxt;
}e[M<<1];
void add(int u,int v,int w){
e[++tot].v=v;
e[tot].w=w;
e[tot].nxt=head[u];
head[u]=tot;
}
void add_e(int u,int v,int w){
add(u,v,w);
add(v,u,0);
}
namespace Max_Flow{
int cur[N<<1],dep[N<<1];
bool bfs(){
queue<int>q;
for(int i=1;i<=T;i++){
dep[i]=0;
}
dep[S]=1;
q.push(S);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(!dep[v]&&w){
dep[v]=dep[u]+1;
if(v==T){
return 1;
}
q.push(v);
}
}
}
return 0;
}
int dfs(int u,int flow){
if(u==T){
return flow;
}
int ans=0;
for(int i=cur[u];i;i=e[i].nxt){
cur[u]=i;
int v=e[i].v,w=e[i].w;
if(dep[v]==dep[u]+1&&w){
int res=dfs(v,min(flow,w));
e[i].w-=res;
e[i^1].w+=res;
flow-=res;
ans+=res;
}
if(!flow){
break;
}
}
if(!ans){
dep[u]=0;
}
return ans;
}
int dinic(){
int ans=0;
while(bfs()){
for(int i=1;i<=T;i++){
cur[i]=head[i];
}
ans+=dfs(S,inf);
}
return ans;
}
}
int val[N],id[N][N],vis[N*N],idx,mx=1e9;
void dfs(int u){
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(w&&!vis[v]){
dfs(v);
}
}
}
void solve(){
read(n),read(m);
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++){
id[i][j]=++idx;
}
}
S=++idx,T=++idx;
for(int i=1;i<=n;i++){
add_e(S,id[i][0],inf);
add_e(id[i][n],T,inf);
}
for(int i=1;i<=m;i++){
int u,v,w;
read(u),read(v),read(w);
val[u]+=w;
val[v]-=w;
for(int i=0;i<n;i++){
add_e(id[v][i],id[u][i+1],inf);
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<n;j++){
add_e(id[i][j],id[i][j+1],val[i]*j+mx);
}
}
Max_Flow::dinic();
dfs(S);
for(int i=1;i<=n;i++){
for(int j=n;j>=0;j--){
if(vis[id[i][j]]){
write_space(j);
break;
}
}
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Pawns
因为只能往右移,令 \(b_i=y_i-|x_i-k|\),最终落点 \(a_i\) 一定大于等于 \(b_i\)。可以得到的是一定是一段前缀的后缀最大值,前缀的右端点可以用 set 维护,后缀最大值可以用线段树维护,复杂度 \(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=4e5+10;
int n,k,q,m;
struct node{
int sum,rmx;
}tr[N<<2];
namespace Seg_Tree{
int ls(int p){
return p<<1;
}
int rs(int p){
return p<<1|1;
}
void push_up(int p){
tr[p].sum=tr[ls(p)].sum+tr[rs(p)].sum;
tr[p].rmx=max(tr[rs(p)].rmx,tr[ls(p)].rmx+tr[rs(p)].sum);
}
void build(int p,int l,int r){
tr[p].sum=tr[p].rmx=-1;
if(l==r){
return;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
push_up(p);
}
void update(int p,int l,int r,int pos,int val){
if(l==r){
tr[p].sum+=val;
tr[p].rmx+=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid){
update(ls(p),l,mid,pos,val);
}
else{
update(rs(p),mid+1,r,pos,val);
}
push_up(p);
}
node query(int p,int l,int r,int pos){
if(r<=pos){
return tr[p];
}
int mid=(l+r)>>1;
if(pos<=mid){
return query(ls(p),l,mid,pos);
}
node res,ansl,ansr;
ansl=query(ls(p),l,mid,pos);
ansr=query(rs(p),mid+1,r,pos);
res.sum=ansl.sum+ansr.sum;
res.rmx=max(ansr.rmx,ansl.rmx+ansr.sum);
return res;
}
}
multiset<int>s;
map<pii,bool>vis;
void solve(){
read(n),read(k),read(q);
m=n+q;
Seg_Tree::build(1,1,m);
while(q--){
int x,y;
read(x),read(y);
int opt=vis[mp(x,y)]?-1:1,p=y+abs(k-x);
vis[mp(x,y)]+=opt;
Seg_Tree::update(1,1,m,p,opt);
// cerr<<x<<' '<<y<<' '<<opt<<endl;
if(opt==1){
s.insert(p);
}
else{
s.erase(s.find(p));
}
if(!s.size()){
write_endl(0);
continue;
}
int mx=max(n,*(--s.end()));
node res=Seg_Tree::query(1,1,m,mx);
write_endl(max(0,mx-n+res.rmx));
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
[ABC308G] Minimum Xor Pair Query
好题。但是真学ds学的了,一眼线段树分治+trie。
这题有个关键性结论:若存在 \(x<y<z\),\(\min(x\oplus y,y\oplus z)\le x\oplus z\)。证明的话,将所有数放到trie上,对于一个数,如果找其的异或最小值,一定贪心的往当前位的值的方向走,即会走到排序后与它相邻的点。
用两个set,一个维护值,一个维护相邻两个数的异或和。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
multiset<int>s,val;
int n;
void solve(){
read(n);
for(int i=1;i<=n;i++){
// cerr<<i<<endl;
int opt,x;
read(opt);
if(opt==1){
read(x);
if(!val.size()){
val.insert(x);
continue;
}
// cerr<<"HAHA"<<endl;
int mn=*val.begin();
if(x<mn){
s.insert(mn^x);
val.insert(x);
continue;
}
auto it=val.lower_bound(x);
if(it==val.end()){
it--;
s.insert((*it)^x);
val.insert(x);
continue;
}
int y=*it,z=*(--it);
val.insert(x);
s.insert(y^x);
s.insert(z^x);
s.erase(s.find(y^z));
}
else if(opt==2){
read(x);
val.erase(val.find(x));
if(!val.size()){
continue;
}
int mn=*val.begin();
if(x<mn){
s.erase(s.find(mn^x));
continue;
}
auto it=val.lower_bound(x);
if(it==val.end()){
it--;
s.erase(s.find((*it)^x));
continue;
}
int y=*it,z=*(--it);
s.erase(s.find(y^x));
s.erase(s.find(z^x));
s.insert(y^z);
}
else{
write_endl(*s.begin());
}
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}