2021牛客暑期多校训练营7
F-xay loves trees
思路
参考:2021牛客暑期多校训练营7 F - xay loves trees - naymi - 博客园 (cnblogs.com)
显然这些点在第一棵树上必然是一条链,所以我们用双指针维护这棵树上的一条链;对于这条链,判断其在第二棵树上是否满足条件的方法是:对于链上的每个节点,将其在第二棵树上以该点为根的子树全部染色(值+1),那么某个节点子树的最大值若是0,就可以加入链(并对子树染色),否则不能加入链(说明要么它的父节点已经染色,要么它有个子节点已染色)。对于第一颗树的操作可以用deque维护,第二棵树则可以用树链剖分+线段树维护最大值来解决。
搞了两天终于把这道树链剖分搞出来了qwq
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
struct line_tree
{
struct node
{
int l, r, mx, add;
} tr[N * 4];
void pushup(int u)
{
tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx);
}
void build(int u, int l, int r)
{
tr[u] = {l, r, 0, 0};
if(l == r)
return ;
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void pushdown(int u)
{
auto &root = tr[u],
&lson = tr[u << 1],
&rson = tr[u << 1 | 1];
if(!root.add)
return ;
lson.add += root.add;
lson.mx += root.add;
rson.add += root.add;
rson.mx += root.add;
root.add = 0;
}
void modify(int u, int l, int r, int d)
{
if(tr[u].l >= l && tr[u].r <= r)
{
tr[u].add += d;
tr[u].mx += d;
return ;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid)
modify(u << 1, l, r, d);
if(r > mid)
modify(u << 1 | 1, l, r, d);
pushup(u);
}
int query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r)
return tr[u].mx;
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
int ans = 0;
if(l <= mid)
ans = max(ans, query(u << 1, l, r));
if(r > mid)
ans = max(ans, query(u << 1 | 1, l, r));
return ans;
}
} line;
struct tree_chain2
{
int head[N], nxt[N], top[N], es[N],
wson[N], sz[N], dep[N], dfsn[N],
par[N], tot, idx;
void init()
{
idx = 0;
tot = 0;
memset(head, -1, sizeof head);
memset(nxt, 0, sizeof nxt);
memset(dep, 0, sizeof dep);
memset(wson, 0, sizeof wson);
}
void addEdge(int u, int v)
{
es[++idx] = v;
nxt[idx] = head[u];
head[u] = idx;
}
void dfs1(int u, int fa)
{
sz[u] = 1;
for(int i = head[u]; ~i; i = nxt[i])
{
int v = es[i];
if(v == fa)
continue;
dep[v] = dep[u] + 1;
par[v] = u;
dfs1(v, u);
sz[u] += sz[v];
if(sz[wson[u]] < sz[v])
wson[u] = v;
}
}
void dfs2(int u, int tp)
{
dfsn[u] = ++tot;
top[u] = tp;
if(wson[u])
dfs2(wson[u], tp);
for(int i = head[u]; ~i; i = nxt[i])
{
int v = es[i];
if(v == par[u] || v == wson[u])
continue;
dfs2(v, v);
}
}
void modify(int x, int d) //x子树 += d
{
line.modify(1, dfsn[x], dfsn[x] + sz[x] - 1, d);
}
int query(int x) //查询子树的最大值
{
return line.query(1, dfsn[x], dfsn[x] + sz[x] - 1);
}
} chain2;
struct tree_chain1
{
int head[N], nxt[N], es[N], idx, ans;
void init()
{
idx = 0;
ans = 0;
memset(head, -1, sizeof head);
}
void addEdge(int u, int v)
{
es[++idx] = v;
nxt[idx] = head[u];
head[u] = idx;
}
void dfs(int u, int fa, deque<int>& que)
{
ans = max(ans, (int)que.size());
for(int i = head[u]; ~i; i = nxt[i])
{
deque<int> nxtque = que;
stack<int> st;
int v = es[i];
if(v == fa)
continue;
nxtque.push_back(v);
while(chain2.query(v) > 0)
{
chain2.modify(nxtque.front(), -1);
st.push(nxtque.front());
nxtque.pop_front();
}
chain2.modify(v, 1);
dfs(v, u, nxtque);
chain2.modify(v, -1);
while(!st.empty())
{
chain2.modify(st.top(), 1);
st.pop();
}
}
}
} chain1;
int main()
{
int T;
cin >> T;
while(T--)
{
chain1.init();
chain2.init();
int n;
cin >> n;
for(int i = 0, u, v; i < n - 1; i++)
{
cin >> u >> v;
chain1.addEdge(u, v);
chain1.addEdge(v, u);
}
for(int i = 0, u, v; i < n - 1; i++)
{
cin >> u >> v;
chain2.addEdge(u, v);
chain2.addEdge(v, u);
}
chain2.dfs1(1, -1);
chain2.dfs2(1, 1);
line.build(1, 1, n);
deque<int> que;
que.push_back(1);
chain2.modify(1, 1);
chain1.dfs(1, -1, que);
cout << chain1.ans << endl;
}
return 0;
}
H-xay loves count
思路
统计每个数出现的次数,之后对于每个数 i i i 枚举它的倍数 i ∗ k i * k i∗k,其对答案的贡献即: n u m i ∗ n u m k ∗ n u m i ∗ k num_i * num_k * num_{i * k} numi∗numk∗numi∗k 。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6;
int num[N + 10];
int a[N + 10];
ll cnt;
multiset<int> st;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i];
num[a[i]]++;
if(!st.count(a[i]))
st.insert(a[i]);
}
for(auto x : st)
{
for(int i = 1; i * x <= N; i++)
{
cnt += num[i] * num[x] * num[i * x];
}
}
cout << cnt << endl;
return 0;
}
I-xay loves or
思路
按位枚举,若这一位 X X X 是 1 1 1 、 S S S 也是 1 1 1,则 Y Y Y 可 0 0 0 可 1 1 1;若这位这一位 X X X 是 1 1 1、 S S S 是 0 0 0,则没有答案。注意 0 0 0 不是正整数, Y Y Y 必须是正整数。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int mod = 5000011;
ll x, s;
int main()
{
scanf("%lld%lld", &x, &s);
ll xx = x, ss = s;
if(x > s)
{
printf("0\n");
return 0;
}
bool flag = 0;
ll ans = 1;
while(x && s)
{
if((x & 1) == 1 && (s & 1) == 0)
{
flag = 1;
break;
}
if((x & 1) && (s & 1))
{
ans = ans * 2;
}
x >>= 1;
s >>= 1;
}
if(flag)
{
printf("0\n");
return 0;
}
if(xx == ss)
ans--;
printf("%lld\n", ans);
return 0;
}