给你一个不超过 \(10^9\) 的数字 \(n\) 和一个交换次数上限 \(k\),node
每次操做对这个 数字 \(n\) 的其中两位进行交换,ios
好比 201 能够换成 102,git
让你进行 \(k\) 次操做,求出交换后最大的数字和最小的数字的差的绝对值。网络
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <string.h> using namespace std; #define int long long const int manx=1e6+10; const int mamx = 1e6 + 11; const int mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int t,n,m,now[manx],cnt,maxn,minx,k; int a[manx],b[manx],js,bz; void dfs_min(int k,int cnt){ if(k <= 0 || cnt >= js){ int s = 0; for(int i = 1;i <= js;i++) s = s*10 + b[i]; if(s > bz) minx = min(s,minx);//s-->minx,100 --> 0 /* bz : 标准 含义是当前这个序列组成的数必须比 10^(js-1)大,(防止前导零) */ return; } for(int i = cnt + 1;i <= js; i++){ if(b[i] <= b[cnt]){ swap(b[i],b[cnt]); dfs_min(k-1,cnt+1); swap(b[i],b[cnt]);//回溯 } } dfs_min(k,cnt+1);//当前这个数即为最小数,直接搜索下一位 } void dfs_max(int k,int cnt){ if(k <= 0 || cnt >= js){ int s = 0; for(int i = 1;i <= js;i++) s = s*10 + a[i]; maxn = max(maxn,s); return; } for(int i = cnt + 1;i <= js; i++){ if(a[i] >= a[cnt]){ swap(a[i],a[cnt]); dfs_max(k-1,cnt+1); swap(a[i],a[cnt]); } } dfs_max(k,cnt+1);//原理同上 } void solve(){ memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(now,0,sizeof(now)); cnt = js = 0; minx = inf, maxn = 0; n = read();k = read(); while(n){ now[++cnt] = n%10; //倒序去位数 n = n/10; } bz = 1; for(int i = cnt;i >= 1; i--){ a[++js] = now[i],b[js] = now[i];//不能够连等吗 bz *= 10; } bz = bz/10;//位数是(js-1) dfs_max(k,1),dfs_min(k,1); cout<< maxn - minx << '\n'; } signed main(){ t = read(); while(t--) solve(); return 0; }
咱们把从 \(u\) 到 \(u+k\) 做为一组,叫作操做oop
那么第 \(i\) 次和第 \(i+1\) 次操做同时进行的话,那么获得翻转的数只有 \(i\) 和 \(i+k\)优化
所以同时翻转任意距离 \(k\) 的操做就等价于“翻转任意连续 K 盏灯的状态”ui
等价的缘由spa
“翻转任意连续 K 盏灯的状态” 是由一次 \(<a>\), 和若干个 \(<b>\) 操做组成code
而且 \(<b>\) 操做还分红了固定的几组,所以能够全面的操做到每一位ci
每一次 \(<b>\) 操做都订价与翻转一组相邻 \(k\) 的两盏灯,且组与组之间没有影响
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const int manx=1e6+10; const int mamx = 1e6 + 11; const ll mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1; for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48); return x * f; } int T ,a[manx] ,n ,k ,ans; bool pd[manx]; inline int Check(int n ,int k ,bool pd[] ,int a[]){ int ret = 0; for(int i = 1;i <= k;i ++){ int cnt = 0,minx = inf; for(int j = i; j <= n; j+=k){ ret += a[j]; minx = min(minx ,a[j]); if(pd[j] == 0) cnt++;//记录零的个数 } if(cnt % 2 != 0) ret -= minx; } return ret; } int main(){ T = read(); while(T--){ ans = 0; n = read(); k = read(); for(int i = 1;i <= n; i++) pd[i] = read(); for(int i = 1;i <= n; i++) a[i] = read(); if(k == 1){ for(int i =1;i <= n; i++) ans += a[i]; }else{ ans = Check(n ,k ,pd ,a); /* 两种状况,第一个是不翻转1-k,获得的最小值, 第二个是翻转后获得的最小值, (由于就两种状况前 1-k 翻与不翻) */ for(int i = 1;i <= k; i++) pd[i] ^= 1;//pd [i] ---> pd [k] 100 --> 0 ans = max(ans,Check(n ,k ,pd ,a)); } cout<<ans<<'\n'; } return 0; }
显然能够用树链剖分进行操做,和线段树进行维护,
路径修改,求子树间两点路径的总和(不是子树查询)
值得注意的是,点权变边权,操做路径修改是要注意 \(dfn[u]\) 的位置,避免多加,或少加
不妨设点 \(x\) 与它的父亲 \(fa[x]\) 相连的边的权值为 \(p[x]\),
考虑 \(p[x]\) 会对那些点对产生贡献?
显然是通过 \(x——fa[x]\) 这条边的那些点对。记 \(size_[x]\) 为以 \(x\) 为根的子树的大小。
则通过 \(x——fa[x]\) 的点对有 \(size_[x]×(size_[i] – size_[x])\) 对
因而,子树 \(i\) 内的点 \(x\) 的贡献
#include <iostream> #include <cstdio> #include <cstring> #include <string.h> #include <queue> #include <algorithm> using namespace std; #define ll long long const int manx = 1e6; const int mod = 2123400401301379571; const int inf = 0x3f3f3f3f; inline int read(){ char c = getchar(); int x = 0, f = 1; for( ;!isdigit(c);c = getchar()) if(c == '-') f = -1; for( ;isdigit(c);c = getchar()) x = x*10 + (c^48); return x * f; } struct node{ int v,nxt; }e[manx]; int head[manx],cnt,n,m,dep[manx],fa[manx],size_[manx],val[manx],pre[manx],tp[manx],dfn[manx],hson[manx]; int js,sigma1,sigma2; inline void add(int u,int v){ e[++cnt].nxt = head[u]; e[cnt].v = v; head[u] = cnt; } namespace Tree{ #define ls i<<1 #define rs i<<1|1 struct tree{ int l;int r; ll sum,lazy; }tr[manx<<3]; inline void up(int i){ tr[i].sum = tr[ls].sum + tr[rs].sum ; } inline void down(int i){ if(tr[i].lazy){ ll x = tr[i].lazy ; tr[ls].sum += (tr[ls].r - tr[ls].l +1)*x; tr[rs].sum += (tr[rs].r - tr[rs].l +1)*x; tr[ls].lazy += x; tr[rs].lazy += x; tr[i].lazy = 0; } } inline void build(int i,int l,int r){ tr[i].l = l;tr[i].r = r; if(l == r){ tr[i].sum = val[pre[l]]; return ; } int mid = (l + r)>>1; build(ls,l,mid); build(rs,mid+1,r); up(i); } inline void add(int i,int l,int r,int w){ if(tr[i].l >= l && tr[i].r <= r){ tr[i].sum += (tr[i].r - tr[i].l +1)*w; tr[i].lazy += w; return; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= r)add(ls,l,r,w); else if(mid < l)add(rs,l,r,w); else add(ls,l,mid,w),add(rs,mid+1,r,w); up(i); } inline ll only_query(int i,int u){ if(tr[i].l == tr[i].r ){ return tr[i].sum ; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= u) return only_query(ls,u); else if(mid < u) return only_query(rs,u); } inline ll query(int i,int l,int r){ if(tr[i].l >= l && tr[i].r <= r){ return tr[i].sum ; } down(i); int mid=(tr[i].l +tr[i].r )>>1; if(mid >= r)return query(ls,l,r); else if(mid < l)return query(rs,l,r); return query(ls,l,mid)+query(rs,mid+1,r); } } namespace Node{ inline void dfs1(int u,int pre,int d){ fa[u] = pre; dep[u] = d;size_[u] = 1; for(int i = head[u]; i;i = e[i].nxt){ int v = e[i].v ; if(v != pre){ dfs1(v,u,d+1); size_[u] += size_[v]; if(!hson[u] || size_[hson[u]] < size_[v]){ hson[u] = v; } } } } inline void dfs2(int u,int top){ tp[u] = top; dfn[u] = ++js; pre[js] = u; if(!hson[u])return; dfs2(hson[u],top); for(int i = head[u];i;i = e[i].nxt ){ int v = e[i].v ; if(v != fa[u] && v != hson[u]){ dfs2(v,v); } } } inline void add(int u,int v,int w){ while(tp[u] != tp[v]){ if(dep[tp[u]] < dep[tp[v]])swap(u,v); Tree::add(1,dfn[tp[u]],dfn[u],w); u = fa[tp[u]]; } if(dep[u]>dep[v])swap(u,v); Tree::add(1,dfn[u] + 1,dfn[v],w); } inline void query(int u){ for(int i = head[u]; i; i = e[i].nxt ){ int v = e[i].v ; if(v != fa[u]){ Node::query(v); int s = Tree::only_query(1,dfn[v]); // cout<<s<<" "<<v<<endl; sigma1 += (s * size_[v]); sigma2 += (s * size_[v] * size_[v]); } } return; } } char a[9]; int main(){ //freopen("pp.in","r",stdin); //freopen("network.out","w",stdout); n = read();m = read(); for(int i = 1;i < n; i++){ int x = read(), y = read(); val[i+1] = y; add(i+1,x); add(x,i+1); } Node::dfs1(1,0,1),Node::dfs2(1,1),Tree::build(1,1,n); for(int i = 1;i <= m; i++){ cin>>a; ll ans = 0; ll fan = 0; int x,y,z; if(a[0] == 'I'){ x = read(); y = read(); z = read(); Node::add(x,y,z); }else{ x = read(); sigma1 = 0; sigma2 = 0; Node::query(x); cout<<size_[x] * sigma1 - sigma2 <<endl; } } return 0; }
感谢观看