2017ACM/ICPC Guangxi Invitational Solution
A: A Math Problem
题意:给出一个n,找出有多少个k满足kk <= n
思路: kk的增长很快,当k == 16 的时候就已经超过1e18 了,对于每一次询问,暴力一下就可以
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll n; inline ll qpow(ll x, ll n)
{
ll ans = ;
ll base = x;
while (n)
{
if (n & ) ans = ans * base;
base = base * base;
n >>= ;
}
return ans;
} int main()
{
while (scanf("%lld", &n) != EOF)
{
int i;
for (i = ; i <= ; i++)
{
if (qpow(i, i) > n)
{
i--;
break;
}
}
if (i == ) i--;
printf("%d\n", i);
}
}
B:Color it
题意:给出四种操作,
0 清空所有点
1 x y c 往(x, y) 处插入一个颜色为c的点
2 x y1 y2 查询(1, y1) 到(x, y2) 这个矩形里面有多少个颜色不同的点
3 退出程序
思路: 很显然 操作0 相当于多组样例 操作3是退出程序 故我们只需要考虑第1种操作和第2种操作
因为查询的范围当中x的左界是固定的,我们可以想到以y坐标轴来建线段树
因为只有51种颜色,我们考虑建51棵线段树,然后每次保存离左边界最近的横坐标,看看那个y1 - y2 那个区间内是否存在一个x' < x
存在的话就有这种颜色
然后开五十棵线段树,会爆内存,但是可以想到,每次更新最多增加log(n)的点,操作数量的上限也才150000, 故可以动态开点
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f
#define N 1000100 struct node
{
int l, r, v;
inline node()
{
l = , r = , v = INF;
}
inline node(int l, int r, int v) : l(l), r(r), v(v) {}
}tree[N << ]; int root[];
int cnt, tag; inline void Init()
{
for (int i = ; i <= cnt; ++i)
tree[i] = node();
memset(root, , sizeof root);
cnt = ;
} inline void update(int &id, int l, int r, int x, int y)
{
if (id == )
{
id = ++cnt;
tree[id].v = x;
}
tree[id].v = min(tree[id].v, x);
if (l == r) return;
int mid = (l + r) >> ;
if (y <= mid) update(tree[id].l, l, mid, x, y);
else update(tree[id].r, mid + , r, x, y);
} inline void query(int id, int l, int r, int ql, int qr, int x)
{
if (id == || tag) return;
if (l >= ql && r <= qr)
{
if (tree[id].v <= x)
tag = ;
return;
}
int mid = (l + r) >> ;
if (ql <= mid) query(tree[id].l, l, mid, ql, min(mid, qr), x);
if (qr > mid) query(tree[id].r, mid + , r, max(ql, mid + ), qr, x);
} int main()
{
int op, x, y1, y2, c;
while (scanf("%d", &op) != EOF)
{
if (op == ) return ;
if (op == )
{
Init();
}
if (op == )
{
scanf("%d%d%d", &x, &y1, &c);
update(root[c], , , x, y1);
}
if (op == )
{
scanf("%d%d%d", &x, &y1, &y2);
if (y1 > y2) swap(y1, y2);
int ans = ;
for (int i = ; i <= ; ++i)
{
tag = ;
query(root[i], , , y1, y2, x);
if (tag)
{
ans++;
}
}
printf("%d\n", ans);
}
}
return ;
}
C:Counting Stars
题意:给出一个无向图,没有重边,求有多少个"A-structure"结构。"A-structure"是指一个4个点的子图,这4个点依次连接,且有一条斜边。只要有任意一条边或一个点不同,则认为它们是不同的。
思路:选取一条边作为斜边,统计这个斜边上有多少个三元环,记为sum,那么以这个边为斜边的"A-structure"共有(sum-1)*sum/2个。但是直接枚举每条边找环的时间复杂度在完全图下可达m^2的级别,
这显然是不行的。枚举点x,然后枚举与x相邻的点y,这样相当于枚举了每条边,然后当x的度小于sqrt(m)时,我们可以用O(1)的时间判断y是否与x其他相邻的点组成三元环,而当x的度大于sqrt(m)时,我们
可以枚举与y相邻的点z,用set判断x与z是否有边。因为m≤min(2×105,n(n−1)/2),所以度大于sqrt(m)的点不会很多,这样时间复杂度就是msqrt(m)了。
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std; const int N = ;
vector<int> g[N];
set<long long> p;
int fa[N], f[N], du[N];
int main() {
int n, m, i, j, k, x, y;
long long ans, sum;
while (scanf("%d %d", &n, &m) != EOF)
{
ans = ; p.clear();
for (i = ; i <= n; ++i)
{
f[i] = fa[i] = du[i] = ; g[i].clear();
}
for (i = ; i <= m; ++i)
{
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
p.insert((long long)x*n + y);
p.insert((long long)y*n + x);
du[x]++; du[y]++;
}
for (i = ; i <= n; ++i)
{
f[i] = ;
for (j = ; j < du[i]; ++j) fa[g[i][j]] = i;
for (j = ; j < du[i]; ++j)
{
x = g[i][j];
if (f[x] == ) continue;
sum = ;
if (du[x] <= (int) sqrt(m))
{
for (k = ; k < du[x]; ++k)
if (fa[g[x][k]] == i) sum++;
}
else
{
for (k = ; k < du[i]; ++k)
if (p.find((long long)x*n + g[i][k]) != p.end()) sum++;
}
ans += (sum - )*sum / ;
}
}
printf("%lld\n",ans);
}
return ;
}
D:Covering
题意:求用 1 * 2 和 2 * 1 的方块填充 4 * n 的矩形,求有多少方法
思路:n很大,显然是log(n)的做法,猜测应该是矩阵快速幂递推。用搜索或者状压DP暴力出前几项,发现前几项是这样的
1 1
2 5
3 11
4 36
5 95
6 281
7 781
满足递推式 F[n] = F[n - 1] + 5 * F[n - 2] + F[n - 3] - F[n - 4];
然后构造矩阵 矩阵快速幂一下
#include <bits/stdc++.h> using namespace std; #define ll long long const int MOD = (int)1e9 + ; struct node
{
ll a[][];
inline node()
{
memset(a, , sizeof a);
}
inline node operator * (const node& r) const
{
node ans = node();
for (int i = ; i < ; ++i)
for (int j = ; j < ; ++j)
for (int k = ; k < ; ++k)
ans.a[i][j] = (ans.a[i][j] + (a[i][k] * r.a[k][j] + MOD) % MOD + MOD) % MOD;
return ans;
}
}; ll arr[][] =
{
, , , ,
, , , ,
, , , ,
-, , , ,
}; inline node qpow(ll n)
{
node ans = node();
ans.a[][] = , ans.a[][] = , ans.a[][] = , ans.a[][] = ;
node base = node();
for (int i = ; i < ; ++i)
for (int j = ; j < ; ++j)
base.a[i][j] = arr[i][j];
while (n)
{
if (n & ) ans = ans * base;
base = base * base;
n >>= ;
}
return ans;
} ll n; int main()
{
while (scanf("%lld", &n) != EOF)
{
if (n == ) puts("");
else if (n == ) puts("");
else if (n == ) puts("");
else if (n == ) puts("");
else
{
node ans = qpow(n - );
printf("%lld\n", ans.a[][]);
}
}
return ;
}
E:CS Course
题意:给出n个数,然后有q次查询,每次查询给出一个p,要求输出这n个数中,去掉第p个数的所有数分别进行按位与运算,按位异或运算,按位或运算的和
思路:首先考虑按位异或运算,根据异或运算的性质,我们只需要先预处理出所有数的异或和,然后每次输出时异或一下第p个数就行了 因为这样第p个数就异或了两次,相当于没有异或
再考虑按位与运算 我们也是先处理出所有数相与之后的那个和, 并且开一个数组记录一下每个二进制位上为1的数有多少, 再考虑以下几种情况
为了方便,我们假设第p个数为A,所有数相与之后的和为B,接下来我们再按二进制位考虑
1° 对于某一位上,B为0,并且A为0,并且所有数那一位上为1的个数为n - 1 那么我们可以知道,如果去掉A,那么剩下的数相与,那一位上肯定是1
2° 对于某一位上,B为1,很显然,去掉A之后,肯定也会为1
3° 对于某一位上,B为0,并且不满足第一种情况,那只能为0
按位或运算的思考方法和按位与运算思考方法差不多,此处故不再给出。
#include <bits/stdc++.h> using namespace std; #define N 100010
#define ll long long int n, q; ll arr[N]; int a[]; int main()
{
while (scanf("%d%d", &n, &q) != EOF)
{
ll Xor = , And, Or = ;
memset(a, , sizeof a);
for (int i = ; i <= n; i++)
{
scanf("%lld", arr + i);
Xor ^= arr[i];
if (i == ) And = arr[];
else And &= arr[i];
Or |= arr[i];
ll tmp = arr[i];
for (int j = ; j <= ; j++)
{
a[j + ] += (tmp & (1ll << j)) ? : ;
if ((1ll << j) > tmp) break;
}
}
// for (int i = 0; i <= 40; i++) printf("%d%c", a[i], " \n"[i == 40]);
// printf("%lld %lld %lld\n", Xor, And, Or);
int p;
while (q--)
{
scanf("%d", &p);
ll aa = Xor ^ arr[p];
ll bb = ; ll cc = ;
for (ll i = ; i <= ; i++)
{
if ((And & (1ll << i)) == && a[i + ] == n - && (arr[p] & (1ll << i)) == ) bb += (1ll << i);
else if (And & (1ll << i)) bb += (1ll << i);
if ((Or & (1ll << i)) && a[i + ] == && (arr[p] & (1ll << i))) continue;
if ((Or & (1ll << i)) == ) continue;
cc += (1ll << i);
// printf("%lld %lld\n", bb, cc);
}
// cout << "bug\n";
printf("%lld %lld %lld\n", bb, cc, aa);
}
}
return ;
}
F:Destory Walls
题意:给出国王所在的坐标,以及一些点,再给出一些边,表示两个点之间有一堵墙,然后国王想拆掉一些墙,使得所有区域连通,使得拆掉墙的数量最少以及花费最少,没给出的边就说明两个点之间没有墙
思路:对偶图,是把面看成点,面与面之间连边,那么我们可以想到,如果给出的边关系构成的图没有环的话,那么只有一个面,也就是说所有区域都是连通的,那么我们就是想办法留下一棵树,使得边数尽量多,上面的权值和尽量大
那就是求一棵最大生成树
#include <bits/stdc++.h>
using namespace std; #define N 100010
#define ll long long int n, m;
int pre[N];
ll tot; inline int find(int x)
{
if (pre[x] != x)
pre[x] = find(pre[x]);
return pre[x];
} struct Edge
{
int u, v; ll w;
inline void scan()
{
scanf("%d%d%lld", &u, &v, &w);
tot += w;
}
inline bool operator < (const Edge &r) const
{
return w > r.w;
}
}edge[N << ]; inline void Run()
{
while (scanf("%d%d", &n, &m) != EOF)
{
tot = ;
for (int i = , x, y; i <= n; ++i) scanf("%d%d", &x, &y), pre[i] = i;
for (int i = ; i <= m; ++i) edge[i].scan();
sort(edge + , edge + + m);
int cnt = ; ll sum = ;
for (int i = ; i <= m; ++i)
{
int u = edge[i].u, v = edge[i].v;
u = find(u), v = find(v);
if (u == v) continue;
++cnt; sum += edge[i].w;
pre[u] = v;
}
printf("%d %lld\n", m - cnt, tot - sum);
} } int main()
{
#ifdef LOCAL
freopen("Test.in", "r", stdin);
#endif Run(); return ;
}
G:Duizi and Shunzi
题意: 有n个数,两个相同的数可以组成一个对子,三个连续的数可以组成一个顺子,数字不可以重复使用,求最后可以组成多少对对子和顺子
思路:贪心,我们优先的想法肯定是组对子,然后再是组顺子。因为组对子花的数少,组顺子花的数多。
#include <bits/stdc++.h> using namespace std; #define N 1000010
#define ll long long int n; ll arr[N]; int main()
{
while (scanf("%d", &n) != EOF)
{
memset(arr, , sizeof arr);
for (int i = , num; i <= n; i++)
{
scanf("%d", &num);
arr[num]++;
}
ll ans = ;
for (int i = ; i <= n; ++i)
{
ans += arr[i] / ;
ans += arr[i + ] / ;
arr[i] %= ; arr[i + ] %= ;
if (arr[i] && arr[i + ] && arr[i + ])
{
ans++;
arr[i + ]--;
arr[i + ]--;
}
}
printf("%lld\n", ans);
}
return ;
}
H - Law of Commutation
题意:给出n和a,求有多少个b 满足 $a^b \equiv b^a \pmod m$
思路:当a是奇数的时候 答案是1(我不知道为啥)
当a是偶数的时候 我们令 $a = 2 \cdot x$
那么 $a^b = 2^b \cdot x^b$
显然 当 b > n 的时候 $a^b \equiv 0 \pmod m$
那么当 b <= n 的时候 我们直接暴力
当b > n的时候 如果存在答案 那么有 $b^a \equiv 0 \pmod m$
那么 $b^a 是 m$ 的倍数 又 $m = 2 ^ n$
所以 b 一定是 $2 ^ {\frac{n}{a}}$ (向上取整,我不知道为啥) 的倍数
#include <bits/stdc++.h>
using namespace std; #define ll long long int n;
ll a; inline ll qpow(ll x, ll n, ll MOD)
{
ll base = x;
ll ans = ;
while (n)
{
if (n & ) ans = ans * base % MOD;
base = base * base % MOD;
n >>= ;
}
return ans;
} inline void Run()
{
while (scanf("%d%lld", &n, &a) != EOF)
{
if (a & )
{
puts("");
continue;
}
ll ans = ;
ll m = 1ll << n;
for (int i = ; i <= n; ++i) if (qpow(a, i, m) == qpow(i, a, m))
++ans;
ll tmp = (ll)ceil(n * 1.0 / a);
tmp = 1ll << tmp;
ans += (m / tmp - n / tmp);
printf("%lld\n", ans);
}
} int main()
{
#ifdef LOCAL
freopen("Test.in", "r", stdin);
#endif Run(); return ;
}
I:Matching in a Tree
留坑。
J:Query on A Tree
题意:给出一个树,有n个结点和q次询问,每次给出一个u和一个x,要在以结点u为根节点的子树中(包含u)中找出一个数与x异或后最大,输出异或后的数
思路:子树,自然想到用DFS序来处理这棵树,使得所有的儿子都在连续的一段区间里面,然后用可持久化Trie树去找异或最大
#include <bits/stdc++.h> using namespace std; #define N 100010
#define ll long long struct Edge
{
int to, nx;
inline Edge() {}
inline Edge(int to, int nx) : to(to), nx(nx) {}
}edge[N << ]; int head[N], tot, pos, cnt;
int fa[N], son[N], ord[N], ford[N];
int root[N]; struct node
{
int son[], Count;
inline node()
{
memset(son, , sizeof son);
Count = ;
}
}tree[N * ]; inline void Init()
{
memset(head, -, sizeof head);
pos = ; tot = , cnt = ;
tree[] = node();
} inline void addedge(int u, int v)
{
edge[++tot] = Edge(v, head[u]); head[u] = tot;
} int n, q;
ll w[N]; inline void DFS(int u)
{
ord[u] = ++pos;
ford[pos] = u;
for (int it = head[u]; ~it; it = edge[it].nx)
{
int v = edge[it].to;
if (v == fa[u]) continue;
DFS(v);
}
son[u] = pos;
} inline void Insert(ll x, int id)
{
bitset <> b; b = x;
root[id] = ++cnt;
tree[cnt] = tree[root[id - ]];
int poss = cnt;
for (int i = ; i >= ; --i)
{
int index = b[i];
tree[++cnt] = tree[tree[poss].son[index]];
tree[cnt].Count++;
tree[poss].son[index] = cnt;
poss = cnt;
}
} inline ll Query(ll x, int l, int r)
{
bitset <> b; b = x;
ll ans = ;
l = root[l], r = root[r];
for (int i = ; i >= ; --i)
{
int index = b[i] ^ ;
bool flag = true;
if (tree[tree[r].son[index]].Count - tree[tree[l].son[index]].Count <= )
{
index ^= ;
flag = false;
}
if (flag) ans += ( << i);
r = tree[r].son[index]; l = tree[l].son[index];
}
return ans;
} int main()
{
while (scanf("%d%d", &n, &q) != EOF)
{
Init();
for (int i = ; i <= n; ++i) scanf("%lld", w + i);
for (int i = , u; i < n; ++i)
{
scanf("%d", &u);
fa[i + ] = u;
addedge(u, i + );
}
DFS();
for (int i = ; i <= n; ++i)
{
Insert(w[ford[i]], i);
}
while(q--)
{
int u; ll x;
scanf("%d%lld",&u,&x);
int l = ord[u] - , r = son[u];
printf("%lld\n",Query(x, l, r));
}
}
return ;
}
#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int N = 2e5 + ; vector<int>G[N]; int n, q; int ord[N], son[N], v[N], get_ord[N];
int index; int trie[N * ][], latest[N * ];
int root[N], tot; inline void init()
{
memset(trie, , sizeof trie);
memset(latest, , sizeof latest);
memset(root, , sizeof root);
tot = ;
index = ;
for (int i = ; i < N; ++i)
{
G[i].clear();
}
} inline void insert(int i, int k, int p, int q)
{
if (k < )
{
latest[q] = i;
return;
}
int c = v[get_ord[i]] >> k & ;
if (p) trie[q][c ^ ] = trie[p][c ^ ];
trie[q][c] = ++tot;
insert(i, k - , trie[p][c], trie[q][c]);
latest[q] = max(latest[trie[q][]], latest[trie[q][]]);
} inline int query(int now, int val, int k, int limit)
{
if (k < )
{
return v[get_ord[latest[now]]] ^ val;
}
int c = val >> k & ;
if (latest[trie[now][c ^ ]] >= limit)
return query(trie[now][c ^ ], val, k - , limit);
else
return query(trie[now][c], val, k - , limit);
} inline void dfs(int u)
{
ord[u] = ++index;
get_ord[index] = u;
for (int i = ; i < G[u].size(); i++)
{
int to = G[u][i];
dfs(to);
}
son[u] = index;
} int main()
{
while (~scanf("%d %d", &n, &q))
{
init();
latest[] = -;
root[] = ++tot;
insert(, , , root[]);
for (int i = ; i <= n; ++i)
{
scanf("%d", &v[i]);
}
for (int i = , u; i <= n; ++i)
{
scanf("%d", &u);
G[u].push_back(i);
}
dfs();
for (int i = ; i <= n; ++i)
{
root[i] = ++tot;
insert(i, , root[i - ], root[i]);
}
while (q--)
{
int u, x;
scanf("%d %d", &u, &x);
printf("%d\n", query(root[son[u]], x, , ord[u]));
}
}
return ;
}
K:Removing Mountains
题意:
给出一个字符串$S$,改变一个位置的字符(可以改成任意字符),使得循环节长度最小。
输出最小循环节长度以及可改动的字符位置
思路:
我们考虑枚举循环节长度$x$,如果有$s[1 \cdots n - x] = s[x + 1 \cdots n]$,那么循环节长度为$x$,并且每个位置都可以改变成原来的字符,其实相当于原串不变
否则我们考虑最长的$y$使得$s[1 \cdots y] = s[x + 1 \cdots x + y]$, 那么我们可以改变$s[y + 1]$或者$s[x + y + 1]$去判断是否能够使得$s[1 \cdots n - x] = s[x + 1 \cdots n]$成立,即至多改变两个位置
#include <bits/stdc++.h>
using namespace std;
#define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0)
void err() { cout << "\033[39;0m" << endl; }
template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); }
const int N = 1e6 + , INF = 0x3f3f3f3f;
int n; char s[N]; typedef unsigned long long ull;
struct Hash {
static ull base[N];
static void init() {
base[] = ;
for (int i = ; i < N; ++i)
base[i] = base[i - ] * ;
}
ull a[N];
inline void gao(char *s) {
a[] = ;
for (int i = ; s[i]; ++i) {
a[i] = a[i - ] * + s[i];
}
}
ull get(int l, int r, int x, int y) {
ull res = a[r] - a[l - ] * base[r - l + ];
if (x >= l && x <= r) {
res -= s[x] * base[r - x];
res += s[y] * base[r - x];
}
return res;
}
}hs;
ull Hash::base[N] = {}; struct ExKMP {
int Next[N];
void get_Next(char *s) {
int lens = strlen(s + ), p = , pos;
Next[] = lens;
while (p + <= lens && s[p] == s[p + ]) ++p;
Next[pos = ] = p - ;
for (int i = ; i <= lens; ++i) {
int len = Next[i - pos + ];
if (len + i < p + ) Next[i] = len;
else {
int j = max(p - i + , );
while (i + j <= lens && s[j + ] == s[i + j]) ++j;
p = i + (Next[pos = i] = j) - ;
}
}
}
}exkmp; int main() {
Hash::init();
while (scanf("%d", &n) != EOF) {
scanf("%s", s + );
exkmp.get_Next(s); hs.gao(s);
if (n == ) {
puts("1 1");
continue;
}
int res = INF, num = INF;
for (int i = ; i <= n; ++i) {
int now = exkmp.Next[i];
if (now == n - i + ) {
res = i - ;
num = n;
break;
} else {
int x = + now, y = i + now, len = n - i + ;
num = ;
num += hs.get(, len, x, y) == hs.get(i, n, x, y);
num += hs.get(, len, y, x) == hs.get(i, n, y, x);
if (num) {
res = i - ;
break;
}
}
}
printf("%d %d\n", res, num);
}
return ;
}
L:Yuno And lrotoridori no Sekai
按题意暴力模拟
#include <bits/stdc++.h>
using namespace std; #define N 1000010 struct Edge
{
int to, nx;
inline Edge() {}
inline Edge(int to, int nx) : to(to), nx(nx) {}
}edge[N << ]; int n, q;
int head[N], pos;
int w[N], path[N], deep[N], fa[N], tot;
int rmq[N << ], F[N << ], P[N << ], cnt;
vector <int> vec; struct ST
{
int mm[N << ];
int dp[N << ][];
inline void init(int n)
{
mm[] = -;
for (int i = ; i <= n; ++i)
{
mm[i] = ((i & (i - )) == ) ? mm[i - ] + : mm[i - ];
dp[i][] = i;
}
for (int j = ; j <= mm[n]; ++j)
{
for (int i = ; i + ( << j) - <= n; ++i)
{
dp[i][j] = rmq[dp[i][j - ]] < rmq[dp[i + ( << (j - ))][j - ]] ? dp[i][j - ] : dp[i + ( << (j - ))][j - ];
}
}
}
inline int query(int a, int b)
{
if (a > b) swap(a, b);
int k = mm[b - a + ];
return rmq[dp[a][k]] <= rmq[dp[b - ( << k) + ][k]] ? dp[a][k] : dp[b - ( << k) + ][k];
}
}st; inline void Init()
{
memset(head, -, sizeof head);
pos = ; deep[] = ; fa[] = ;
} inline void addedge(int u, int v)
{
edge[++pos] = Edge(v, head[u]); head[u] = pos;
edge[++pos] = Edge(u, head[v]); head[v] = pos;
} inline void DFS(int u)
{
deep[u] = deep[fa[u]] + ;
F[++cnt] = u;
rmq[cnt] = deep[u];
P[u] = cnt;
for (int it = head[u]; ~it; it = edge[it].nx)
{
int v = edge[it].to;
if (v == fa[u]) continue;
fa[v] = u;
DFS(v);
F[++cnt] = u;
rmq[cnt] = deep[u];
}
} inline void LCA_Init(int root, int node_num)
{
cnt = ;
DFS(root);
st.init( * node_num - );
} inline int query_lca(int u, int v)
{
return F[st.query(P[u], P[v])];
} inline void query(int u)
{
vec.clear(); vec.push_back(w[u]);
for (int it = head[u]; ~it; it = edge[it].nx)
{
int v = edge[it].to;
vec.emplace_back(w[v]);
}
sort(vec.begin(), vec.end());
} inline void Get(int u, int v)
{
int lca = query_lca(u, v);
tot = ;
path[++tot] = u;
while (u != lca)
{
u = fa[u];
path[++tot] = u;
}
int mid = tot;
while (v != lca)
{
path[++tot] = v;
v = fa[v];
}
reverse(path + + mid, path + + tot);
} inline void add(int v)
{
for (int i = ; i <= tot; ++i)
w[path[i]] += v;
} inline void Reverse()
{
for (int i = , j = tot; i < j; ++i, --j)
swap(w[path[i]], w[path[j]]);
} inline void Run()
{
while (scanf("%d%d", &n, &q) != EOF)
{
Init();
for (int i = ; i <= n; ++i) scanf("%d", w + i);
for (int i = , u, v; i < n; ++i)
{
scanf("%d%d", &u, &v);
addedge(u, v);
}
LCA_Init(, n);
int op, x, y, z;
while (q--)
{
scanf("%d%d%d", &op, &x, &y);
if (op == )
{
query(x);
while (y--)
{
scanf("%d", &x);
printf("%d\n", vec[x - ]);
}
}
else
{
Get(x, y);
if (op == )
Reverse();
else
{
scanf("%d", &z);
add(z);
}
}
}
}
} int main()
{
#ifdef LOCAL
freopen("Test.in", "r", stdin);
#endif Run(); return ;
}
赛后总结:
- 一定要记得return 0, ll
- 如果矩阵快速幂递推的时候,项中有负的,一定要+MOD 再 % MOD,为保险起见,输出答案的时候再% MOD
- 如果用i来表示答案,一定要注意跳出的情况,会不会有越界跳出
- 位运算尽量要加括号,它的优先级最低,进行移位操作的时候,如果爆int了,一定要 1ll << x
- 两个数相与,要么为0,要么为一个> 0 的数; 而不是 要么为0,要么为1 这个想法是错误了
- 在改动了一处之后,一定要仔细思考一下,是否有另一处需要连带改动,不要做无畏的罚时增长
- 对于没有写过的数据结构,但是觉得可做,一定要先想清楚,不可妄想,要用别的类似的数据结构的思想来写,或者一些优秀的数据结构也可以用到题目当中来优化常数
- 尽量不要两个人用两种思路写同一题,尽量先交流好,毕竟只有一台电脑,交流是制胜的关键
- 一定要加强数据结构,图论,数论的练习
- 交题前一定要测试样例,尽量测试边界或极限数据,不能过样例就急着交
2017ACM/ICPC Guangxi Invitational Solution的更多相关文章
- HDU 6227.Rabbits-规律 (2017ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学))
Rabbits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total S ...
- HDU 6225.Little Boxes-大数加法 (2017ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学))
整理代码... Little Boxes Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/O ...
- 2017ACM/ICPC广西邀请赛-重现赛 1007.Duizi and Shunzi
Problem Description Nike likes playing cards and makes a problem of it. Now give you n integers, ai( ...
- 2017ACM/ICPC广西邀请赛-重现赛 1010.Query on A Tree
Problem Description Monkey A lives on a tree, he always plays on this tree. One day, monkey A learne ...
- 2017ACM/ICPC广西邀请赛-重现赛 1004.Covering
Problem Description Bob's school has a big playground, boys and girls always play games here after s ...
- 2017ACM/ICPC亚洲区沈阳站(部分解题报告)
HDU 6225 Little Boxes 题意 计算四个整数的和 解题思路 使用Java大整数 import java.math.BigInteger; import java.util.Scann ...
- 2017ACM/ICPC广西邀请赛-重现赛
HDU 6188 Duizi and Shunzi 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6188 思路: 签到题,以前写的. 实现代码: #inc ...
- 2017ACM/ICPC亚洲区沈阳站-重现赛
HDU 6222 Heron and His Triangle 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6222 思路: 打表找规律+大数运算 首先我 ...
- HDU 6191 2017ACM/ICPC广西邀请赛 J Query on A Tree 可持久化01字典树+dfs序
题意 给一颗\(n\)个节点的带点权的树,以\(1\)为根节点,\(q\)次询问,每次询问给出2个数\(u\),\(x\),求\(u\)的子树中的点上的值与\(x\)异或的值最大为多少 分析 先dfs ...
随机推荐
- 安装ionice v2版本(官方帮助文档)
安装最新的 ionic 命令行工具 npm install -g ionic@latest 官方文档:http://ionicframework.com/docs/v2/getting-started ...
- Qt监控excel
配置文件setup.ini内容 [General] ExcelFilePath=D:/项目资料/GSC-西门子开关/GSCOPC.xlsx GameIp=192.168.1.152 GamePort= ...
- Nutch URL过滤配置规则
nutch网上有不少有它的源码解析,但是采集这块还是不太让人容易理解.今天终于知道怎么,弄的.现在把crawl-urlfilter.txt文件贴出来,让大家一块交流,也给自己备忘录一个. # Lice ...
- C++中的字节对齐分析
struct A { int a; char b; short c; }; struct B { char a; int b; short c; }; #pragma pack(2) struct C ...
- JavaScript中eval()函数
eval调用时,实例为eval( "( javascript代码 )" ), eval() 函数可将字符串转换为代码执行,并返回一个或多个值.
- Error setting expression 'XXX' with value 设置表达式“XXX”时出错 解决方法
1.表达式“xxx”在所调用的action里没有与之对应的对象: 2.action里有该对象作为私有成员变量但是没有get&set方法.
- Atlassian Confluence任意文件读取漏洞
Atlassian Confluence Atlassian Confluence是澳大利亚Atlassian公司的一套专业的企业知识管理与协同软件,也可以用于构建企业WiKi.该软件可实现团队成员之 ...
- MarkDownPad2 key
MarkDownPad2 key : Soar360@live.com GBPduHjWfJU1mZqcPM3BikjYKF6xKhlKIys3i1MU2eJHqWGImDHzWdD6xhMNLGVp ...
- Flash 用FLASH遮罩效果做图片切换效果
本教程是关于FLASH应用遮罩效果制作好看的图片切换效果.该教程选用FLASH遮罩中最简单的一种作为例子,当然你可以用自己的想象力来做出更多更好的图片动画.希望本教程能带你带来帮助. 让我们先看看效果 ...
- ajax跨域终极解决办法!
在使用 ajax 的时候,往往需要通过 ajax 跨域请求一些? 但是 XMLHTTPRequest 是不支持跨域的,所以产生了 JSONP 这个东西来解决跨域,当然解决跨域的方式有很多种.... 第 ...