给定一个数组,每个元素都需要一个颜色染色。每个颜色的得分为染色元素的最大值与最小值的差值,总得分为所有颜色的得分和
对于一个颜色,染色一个元素得分为 0 0 0,染色三个及以上时,除了最大元素与最小元素,其余元素均无贡献,所以一个颜色应该染色两个元素。
对于两种颜色 p , q p,q p,q,四个元素 a ≤ b ≤ c ≤ d a \le b \le c \le d a≤b≤c≤d,可以证明 ( a , d ) , ( b , c ) (a,d),(b,c) (a,d),(b,c) 一定是最优的。
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 1e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int n, a[maxn];
void solve(){
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
sort(a+1, a+1+n);
int ans = 0;
for(int i = 1; i <= (n >> 1); i++)
ans += a[n-i+1] - a[i];
cout << ans << endl;
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
注意到 0 = − 0 0 = -0 0=−0,所以正数将序列分为多段,每一段内如果有负数就进行一次操作。
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 1e6+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
#define int ll
int a[maxn], n;
void solve(){
cin >> n;
int res = 0, len = 0, cnt = 0;
for(int i = 1; i <= n; i++)
cin >> a[i], res += fabs(a[i]);
for(int i = 1; i <= n; i++){
if(a[i] < 0)
len++;
else if(a[i] > 0){
cnt += (len > 0 ? 1 : 0);
len = 0;
}
}
cnt += (len > 0 ? 1 : 0);
cout << res << " " << cnt << endl;
return;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
满二叉树,节点 u u u 的左儿子为 2 u 2u 2u,右儿子为 2 u + 1 2u+1 2u+1 。节点 v v v 的父节点为 ⌊ v 2 ⌋ \lfloor\frac{v}{2}\rfloor ⌊2v⌋
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 1e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
void solve(){
ll n, res = 0;
cin >> n;
while(n){
res += n;
n = n >> 1;
}
cout << res << endl;
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
在 u u u 节点的苹果可以从以 u u u 为根的子树内的叶子节点掉落。
所以预处理每棵子树内的叶子节点数目,叶子节点的度为 1 1 1 。然后可以 O ( 1 ) O(1) O(1) 回答
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 2e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int head[maxn], tot;
struct edge{
int to, nxt;
}e[maxn << 1];
int n, q, a, b;
int deg[maxn], cnt[maxn];
void add(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
void dfs(int u, int fa){
if(deg[u] == 1)
cnt[u] = 1;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa)
continue;
dfs(v, u);
cnt[u] += cnt[v];
}
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i++)
head[i] = deg[i] = cnt[i] = 0;
tot = 0;
deg[1] = 1;
for(int i = 1; i < n; i++){
cin >> a >> b;
add(a, b);
add(b, a);
deg[a]++;
deg[b]++;
}
dfs(1, 0);
cin >> q;
while(q--){
cin >> a >> b;
ll res = 1ll * cnt[a] * cnt[b];
//cout << "ans = ";
cout << res << endl;
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
注意到答案具有单调性,所以可以二分答案。
在 c h e c k check check 的时候,前缀和统计 1 1 1 的数量,然后遍历每个区间判断。
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 1e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int n, m, q;
int op[maxn];
pii s[maxn];
bool check(int x){
vector<int> a(n+1, 0);
vector<int> sum(n+1, 0);
for(int i = 1; i <= x; i++)
a[op[i]] = 1;
for(int i = 1; i <= n; i++)
sum[i] = sum[i-1] + a[i];
for(int i = 1; i <= m; i++){
int l = s[i].fi;
int r = s[i].se;
if(sum[r] - sum[l-1] >= (r-l+1)/2+1)
return true;
}
return false;
}
void solve(){
cin >> n >> m;
for(int i = 1; i <= m; i++)
cin >> s[i].fi >> s[i].se;
cin >> q;
for(int i = 1; i <= q; i++)
cin >> op[i];
int ans = -1;
int l = 1, r = q;
while(l <= r){
int mid = (l+r) >> 1;
if(check(mid)){
r = mid-1;
ans = mid;
}
else
l = mid + 1;
}
//cout << "ans = ";
cout << ans << endl;
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
首先注意到权值只有 1 , − 1 1,-1 1,−1,子区间和的取值是连续的。即如果子区间和最大值为 d m a x dmax dmax,最小值为 d m i n dmin dmin,所有 d m i n ≤ d ≤ d m a x dmin \le d \le dmax dmin≤d≤dmax 的 d d d 都以找到一个子区间,这个子区间的和为 d d d
简单版本询问路径的一个端点一定是根节点,所以可以统计根节点到每个节点路径上的最大区间和与最小区间和。
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 2e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
int n;
int dmin[maxn][2], dmax[maxn][2];
void solve(){
cin >> n;
string op;
int u, x, k, tot = 1;
dmin[1][1] = dmax[1][1] = 1;
for(int i = 1; i <= n; i++){
cin >> op;
if(op == "+"){
cin >> u >> x;
++tot;
dmin[tot][0] = min(dmin[u][0], dmin[u][1]);
dmin[tot][1] = min(x, dmin[u][1]+x);
dmax[tot][0] = max(dmax[u][0], dmax[u][1]);
dmax[tot][1] = max(x, dmax[u][1]+x);
}
else{
cin >> u >> x >> k;
int l = min(dmin[x][0], dmin[x][1]);
int r = max(dmax[x][0], dmax[x][1]);
if(l <= k && k <= r)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
树链剖分,转换成 d f s dfs dfs 序,线段树维护区间信息。
关于线段树维护区间信息,可以看这道题 P4513 小白逛公园
但最大/最小字段和区间不满足交换律,在 lca 处合并时交换一下信息。 调试了好久都没发现这个问题,看了 大佬的文章 才知道的。
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
const int maxn = 2e5+10;
const int maxm = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
inline int ls(int x){return x << 1;}
inline int rs(int x){return x << 1 | 1;}
struct node{
int lmax, rmax, maxv;
int lmin, rmin, minv;
int sum;
node(){}
node(int x){
lmin = rmin = minv = lmax = rmax = maxv = sum = x;
}
}t[maxn << 2];
struct edge{
int to, nxt;
}e[maxn << 1];
struct ask{
int u, v, k;
ask(){}
ask(int u, int v, int k) : u(u), v(v), k(k){}
};
int head[maxn], tot;
int siz[maxn], top[maxn], dep[maxn], fa[maxn], son[maxn];
int dfntot, dfn[maxn], pre[maxn];
int n, w[maxn], cnt;
void add(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
void dfs1(int u, int p){
fa[u] = p;
siz[u] = 1;
dep[u] = dep[p] + 1;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == p)
continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]])
son[u] = v;
}
}
void dfs2(int u, int tp){
top[u] = tp;
dfn[u] = ++dfntot;
pre[dfntot] = u;
if(son[u])
dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa[u] || v == son[u])
continue;
dfs2(v, v);
}
}
void pushup(node &rt, node ls, node rs){
rt.lmax = max(ls.lmax, ls.sum + rs.lmax);
rt.rmax = max(rs.rmax, rs.sum + ls.rmax);
rt.maxv = max(ls.maxv, rs.maxv);
rt.maxv = max(rt.maxv, ls.rmax + rs.lmax);
rt.lmin = min(ls.lmin, ls.sum + rs.lmin);
rt.rmin = min(rs.rmin, rs.sum + ls.rmin);
rt.minv = min(ls.minv, rs.minv);
rt.minv = min(rt.minv, ls.rmin+ rs.lmin);
rt.sum = ls.sum + rs.sum;
}
void build(int k, int l, int r){
if(l == r){
t[k] = node(w[pre[l]]);
return;
}
int mid = (l+r) >> 1;
build(ls(k), l, mid);
build(rs(k), mid+1, r);
pushup(t[k], t[ls(k)], t[rs(k)]);
}
node f(node a, node b){
swap(a.lmin, a.rmin);
swap(a.lmax, a.rmax);
node res;
pushup(res, a, b);
return res;
}
node query(int k, int l, int r, int x, int y){
if(x <= l && y >= r)
return t[k];
else if(y < l || x > r)
return node(0);
int mid = (l+r) >> 1;
node res, lres, rres;
if(x <= mid && y > mid){
lres = query(ls(k), l, mid, x, y);
rres = query(rs(k), mid+1, r, x, y);
pushup(res, lres, rres);
return res;
}
else if(y <= mid)
return query(ls(k), l, mid, x, y);
else
return query(rs(k), mid+1, r, x, y);
}
void query(int x, int y, int d){
node xres(0), yres(0);
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]){
swap(x, y);
swap(xres, yres);
}
node tmp1 = query(1, 1, cnt, dfn[top[x]], dfn[x]);
node tmp2 = xres;
pushup(xres, tmp1, tmp2);
x = fa[top[x]];
}
if(dep[x] > dep[y]){
swap(x, y);
swap(xres, yres);
}
node tmp1 = query(1, 1, cnt, dfn[x], dfn[y]);
node res;
pushup(res, tmp1, yres);
node ans = f(xres, res);
int resmin = ans.minv;
int resmax = ans.maxv;
if(resmin <= d && d <= resmax)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
void init(){
cnt = 1;
tot = dfntot = 0;
for(int i = 0; i <= n+5; i++)
son[i] = head[i] = 0;
}
void solve(){
cin >> n;
string op;
int v, x, u, k;
w[1] = 1;
init();
vector<ask> q;
for(int i = 1; i <= n; i++){
cin >> op;
if(op == "+"){
++cnt;
cin >> v >> x;
add(cnt, v); add(v, cnt);
w[cnt] = x;
}
else{
cin >> u >> v >> k;
q.push_back(ask(u, v, k));
}
}
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, cnt);
for(int i = 0; i < q.size(); i++){
int u = q[i].u;
int v = q[i].v;
int k = q[i].k;
query(u, v, k);
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}