重返橙名…
假如 k ≤ n k\le n k≤n ,那么 k k k应该为偶数.
否则, k − n k-n k−n即为答案.
简单贪心一下.
int n,a,b,c,x,y,z;
int main() {
int T; qr(T); while(T--){
qr(a); qr(b); qr(c);
qr(x); qr(y); qr(z);
int ans=min(c,y);
c -= ans; y -= ans; ans=ans*2;
ans -= min(b,max(z-a-c,0))*2;
pr2(ans);
}
}
设最小值为 m m m,有 若原序列和排序后的序列的某一位置均为 m m m的倍数则合法(因为可以通过 m m m实现任意 m m m倍数的交换) 否则 两个位置上的数必须相等.
int n,a[N],b[N],m;
bool v[N];
int main() {
int _; qr(_); while(_--) {
qr(n); m=inf;
for(int i=1;i<=n;i++) qr(a[i]),b[i]=a[i],m=min(m,a[i]);
sort(b+1,b+n+1); bool flag=1;
for(int i=1;i<=n;i++) {
bool u=a[i]%m==0,v=b[i]%m==0;
if(u) {
flag&=v;
}
else flag&=(a[i]==b[i]);
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
首先,每条边的贡献次数可以 d f s dfs dfs求出.
然后,假如 m ≥ n m\ge n m≥n,则可以贪心的给次数最大的边的权值设为最大.
最后,次数 和 权值 均从大到小选择即可.
int n,m,tot,sz[N],fa[N]; ll f[N],p[N];
vector<int> e[N];
void ins(int x,int y) {e[x].pb(y);}
void add(int x,int y) {ins(x,y); ins(y,x);}
void dfs(int x) {
sz[x]=1;
for(int y:e[x]) if(y^fa[x]) {
fa[y]=x; dfs(y); sz[x]+=sz[y];
f[++tot]=(ll)sz[y]*(n-sz[y]);
}
}
int main() {
int _; qr(_); while(_--) {
qr(n);
for(int i=1;i<=n;i++) e[i].clear();
for(int i=1,x,y;i<n;i++) qr(x),qr(y),add(x,y);
fa[1]=0; tot=0; dfs(1);
qr(m); for(int i=1;i<=m;i++) qr(p[i]);
sort(p+1,p+m+1);
for(int i=m-1;i>=n-1;i--) p[i]=(ll)p[i]*p[i+1]%mod;
m=min(m,n-1);
ll ans=0; sort(f+1,f+tot+1);
while(tot) {
f[tot]%=mod;
if(m) ans += (ll)f[tot]*p[m--]%mod;
else ans += f[tot];
tot--;
}
pr2(ans%mod);
}
return 0;
}
通过画图模拟可以发现:(开始时连通块数 a n s = 1 ans=1 ans=1)
然后就变成了一个二维偏序问题,类似扫描线的思想做即可.
比赛时候打的丑陋的代码:
int n,m;
struct H {
int y,l,r;
bool operator<(H b) const {return y<b.y;}
}a[N];
struct V {
int x,l,r;
};
bool cmp1(V a,V b){return a.r<b.r;}
bool cmp2(V a,V b){return a.l>b.l;}
vector<V> b[2];
const int T=(int)1e6;
struct Bit {
int c[N];
void clear() {memset(c,0,sizeof c);}
void add(int x) { for( ;x<=T+4;x+=x&-x) c[x]++; }
int ask(int x) {int y=0; for( ;x;x&=x-1) y+=c[x]; return y;}
} A,B;
int main() {
qr(n); qr(m);
ll ans=1;
for(int i=1;i<=n;i++) {
qr(a[i].y),qr(a[i].l),qr(a[i].r);
ans += !a[i].l&&a[i].r==T;
}
sort(a+1,a+n+1);
for(int i=1;i<=m;i++) {
int x,l,r; qr(x); qr(l); qr(r);
V t=(V){x,l,r};
b[l>0].pb(t);
if(!l&&r==T) ans++;
}
sort(all(b[0]),cmp1);
sort(all(b[1]),cmp2);
int i=0;
for(auto it:b[0]) {
int x=it.x,l=it.l,r=it.r;
while(i<n&&a[i+1].y<=r) {
++i;
if(!a[i].l) A.add(T-a[i].r+1);
else B.add(a[i].l+1);
}
ans += A.ask(T-x+1)+B.ask(x+1);
}
A.clear(); B.clear();
i=n+1;
for(auto it:b[1]) {
int x=it.x,l=it.l,r=it.r;
while(i>1&&a[i-1].y>=l) {
i--;
if(!a[i].l) A.add(T-a[i].r+1);
else B.add(a[i].l+1);
}
ans += A.ask(T-x+1)+B.ask(x+1);
}
pr2(ans);
return 0;
}
值域那么小,直接用桶排不就行了?
int n,m,c[N+5];
void add(int x,int y) {for( ;x<=N;x+=x&-x) c[x]+=y;}
int ask(int x) {int y=0; for( ;x;x&=x-1) y+=c[x]; return y;}
int ask(int l,int r) {return ask(r)-(l?ask(l-1):0);}
vector<pii> a[N+5],b[N+5];
ll ans=1;
int main() {
qr(n); qr(m);
for(int i=1,x,l,r;i<=n;i++){
qr(x); qr(l); qr(r);
a[l].pb(mk(x,1));
a[r+1].pb(mk(x,-1));
if(!l&&r==N) ans++;
}
for(int i=1,x,l,r;i<=m;i++) {
qr(x); qr(l); qr(r);
b[x].pb(mk(l,r));
if(!l&&r==N) ans++;
}
for(int i=0,t;i<=N;i++) {
for(auto it:a[i]) add(it.fi,it.se);
for(auto it:b[i]) ans += ask(it.fi,it.se);
}
pr2(ans); return 0;
}
我们把序列下标由0开始计,容易发现:
那么我们可以用线段树维护区间和,如果询问一个线段树上的区间 [ l , r ] , 2 k = r − l + 1 [l,r],2^k=r-l+1 [l,r],2k=r−l+1,可以发现 v a l val val的最小的 k k k位并不影响 [ l , r ] [l,r] [l,r]对应的原序列区间,所以我们可以通过异或前面的位找到对应的区间.
至于修改操作,就先 ^ v a l val val,找到对应位置对线段树进行修改即可.
代码来源
这里运用了zkw线段树,所以非常简洁.
#include
using namespace std;
typedef long long ll;
int n,q,val;
ll seg[1<<19|5];
void qr(int &x) {scanf("%d",&x);}
int main() {
scanf("%d%d",&n,&q); n=1<<n;
for(int i=n;i<2*n;i++) scanf("%lld",&seg[i]);
for(int i=n-1; i;i--) seg[i]=seg[i*2]+seg[i*2+1];
while(q--) {
int op,l,r; qr(op); qr(l);
if(op==1) {
l--; l^=val; qr(r);
int delta=r-seg[n+l];
for(int i=n+l; i;i=i/2) seg[i]+=delta;
}
else if(op==2) val^=(1<<l)-1;
else if(op==3) val^=1<<l;
else {
qr(r); l--; ll ans=0;//左闭右开.
for(int a=n+l,b=n+r,c=val;a<b;a/=2,b/=2,c/=2) {
if(a&1) ans+=seg[(a++)^c];
if(b&1) ans+=seg[(--b)^c];
}
printf("%lld\n",ans);
}
}
return 0;
}