# |
Submission time |
Handle |
Problem |
Language |
Result |
Execution time |
Memory |
514838 |
2022-01-18T14:42:50 Z |
blue |
Wells (CEOI21_wells) |
C++17 |
|
156 ms |
311560 KB |
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//one-indexed!!!
const int maxN = 1'500'000;
const int logN = 22;
int N, K;
vector<int> a(maxN);
vector<int> b(maxN);
vector<int> edge[1+maxN];
vector<int> children[1+maxN];
const int MINVALUE = -1e9; //?????????????
struct segtree
{
int l;
int r;
int lp = 0;
int mx = 0;
segtree* left = NULL;
segtree* right = NULL;
segtree()
{
;
}
segtree(int L, int R)
{
l = L;
r = R;
if(l == r) return;
int m = (l+r)/2;
left = new segtree(l, m);
right = new segtree(m+1, r);
}
void add(int L, int R, int V)
{
if(R < l || r < L || R < L) return;
else if(L <= l && r <= R)
{
lp += V;
mx += V;
}
else
{
left->add(L, R, V);
right->add(L, R, V);
mx = lp + max(left->mx, right->mx);
}
}
int rangemax(int L, int R)
{
if(R < l || r < L || R < L) return MINVALUE;
else if(L <= l && r <= R) return mx;
else return lp + max(left->rangemax(L, R), right->rangemax(L, R));
}
};
//Precompute
int curr_ind = 0;
vector<int> order(1);
vector<int> order_index(1+maxN, -1); //direct
vector<int> depth(1+maxN, -1); //give to child
//Postcompute
vector<int> subtree(1+maxN, 1); //initialized to 1!!!!!
int anc[1+maxN][1+logN];
void dfs1(int u)
{
curr_ind++;
order.push_back(u);
order_index[u] = curr_ind;
for(int v: edge[u])
{
if(order_index[v] != -1) continue;
depth[v] = depth[u] + 1;
children[u].push_back(v);
anc[v][0] = u;
dfs1(v);
subtree[u] += subtree[v];
}
}
vector<int> good(1+maxN, 0); //Is the node good? (Is there any path of length K which contains this node?)
segtree S;
void dfs2(int u) //u's processing is done before dfs2(u) is called
{
bool is_good = 0;
if(S.rangemax(1, N) >= K-1)
is_good = 1;
else
{
vector<int> subtree_depths;
for(int v: children[u]) //children
{
subtree_depths.push_back(S.rangemax(order_index[v], order_index[v] + subtree[v] - 1));
}
//remainder of the tree
if(u != 1)
{
int L = S.rangemax(1, order_index[u] - 1); //returns MINVALUE if the interval is empty.
int R = S.rangemax(order_index[u] + subtree[u], N);
subtree_depths.push_back(max(L, R));
}
sort(subtree_depths.begin(), subtree_depths.end());
int DS = (int)subtree_depths.size();
if(DS >= 2)
{
if(subtree_depths[DS-1] + subtree_depths[DS-2] + 1 >= K)
is_good = 1;
}
}
good[u] = is_good;
for(int v: children[u])
{
S.add(1, N, +1);
S.add(order_index[v], order_index[v] + subtree[v] - 1, -2);
dfs2(v);
S.add(1, N, -1);
S.add(order_index[v], order_index[v] + subtree[v] - 1, +2);
}
}
const long long mod = 1'000'000'007LL;
int curr_comp = 0;
vector<int> comp(1+maxN, 0);
vector<int> comp_list[1+maxN];
vector<int> newEdge[1+maxN];
void dfs3(int u)
{
comp[u] = curr_comp;
comp_list[ comp[u] ].push_back(u);
for(int v: edge[u])
{
if(!good[v]) continue;
if(comp[v]) continue;
dfs3(v);
}
}
int lca(int u, int v)
{
if(depth[u] > depth[v]) swap(u, v);
for(int e = logN; e >= 0; e--)
{
if(depth[v] - (1 << e) < depth[u]) continue;
v = anc[v][e];
}
if(u == v) return u;
for(int e = logN; e >= 0; e--)
{
if(anc[u][e] != anc[v][e])
{
u = anc[u][e];
v = anc[v][e];
}
}
u = anc[u][0];
v = anc[v][0];
return u;
}
int dist(int u, int v)
{
return depth[u] + depth[v] - 2*depth[lca(u, v)];
}
const int nopath = -1;
vector<int> visit(1+maxN, 0); //be careful while using this!
vector<int> pathpos(1+maxN, nopath);
vector<int> path;
void pathfinder(int u)
{
// cerr << "pathfinder " << u << '\n';
// cerr << K << '\n';
visit[u] = 1;
path.push_back(u);
if((int)path.size() == K) return;
for(int v: newEdge[u])
{
if(visit[v]) continue;
pathfinder(v);
if((int)path.size() == K) return;
}
path.pop_back();
}
vector<int> new_depth(1+maxN, -1);
vector< vector<int> > desc_list[1+maxN];
int new_anc[1+maxN][1+logN];
int p;
int ordercounter = 0;
vector<int> orderpos(1+maxN, -1);
void add_descendant(int P, int u, int d)
{
while((int)desc_list[P].size() - 1 < d)
desc_list[P].push_back(vector<int>(0));
desc_list[P][d].push_back(u);
}
void new_dfs(int P, int u)
{
for(int v: newEdge[u])
{
if(new_depth[v] != -1) continue; //v is not already visited
if(pathpos[v] != nopath) continue; //v is not on the path.
new_depth[v] = 1 + new_depth[u];
add_descendant(P, v, new_depth[v]);
ordercounter++;
orderpos[v] = ordercounter;
new_anc[v][0] = u;
new_dfs(P, v);
}
}
vector<int> sourcetree[1+maxN];
vector<int> listofdesc[1+maxN];
int currP;
vector<int> path1;
int new_lca(int u, int v)
{
if(new_anc[u][logN] != new_anc[v][logN])
{
u = new_anc[u][logN];
v = new_anc[v][logN];
if(pathpos[u] == currP || pathpos[v] == currP) return u;
if(pathpos[u] > pathpos[v]) swap(u, v);
if(max(pathpos[u], pathpos[v]) < currP) return v;
else if(min(pathpos[u], pathpos[v]) > currP) return u;
else return path1[currP];
}
else
{
if(new_depth[u] > new_depth[v]) swap(u, v);
for(int e = logN; e >= 0; e--)
{
if(new_depth[v] - (1 << e) < new_depth[u]) continue;
v = new_anc[v][e];
}
if(u == v) return u;
for(int e = logN; e >= 0; e--)
{
if(new_anc[u][e] != new_anc[v][e])
{
u = new_anc[u][e];
v = new_anc[v][e];
}
}
u = new_anc[u][0];
v = new_anc[v][0];
return u;
}
}
long long solve(int c)
{
path.clear();
int src = 0;
for(int u: comp_list[c])
if((int)newEdge[u].size() == 1)
{
src = u;
break;
}
long long res = 0;
// cerr << "src = " << src << '\n';
pathfinder(src);
for(int i = 0; i < K; i++)
pathpos[ path[i] ] = i;
path1 = path;
for(int p: path)
{
new_depth[p] = 0;
desc_list[p].push_back(vector<int>(0));
desc_list[p][0].push_back(p);
new_anc[p][0] = p;
ordercounter = 0;
new_dfs(p, p);
}
for(int e = 1; e <= logN; e++)
{
for(int u: comp_list[c])
{
new_anc[u][e] = new_anc[ new_anc[u][e-1] ][e-1];
}
}
for(int f: comp_list[c])
{
if(pathpos[new_anc[f][logN]] + K - (new_depth[f] % K) < K)
sourcetree[f].push_back(path[ pathpos[new_anc[f][logN]] + K - (new_depth[f] % K)]);
if(0 <= pathpos[new_anc[f][logN]] - K + (new_depth[f] % K))
sourcetree[f].push_back(path[ pathpos[new_anc[f][logN]] - K + (new_depth[f] % K)]);
if(new_depth[f] == 0)
sourcetree[f].push_back(f);
}
for(int f: comp_list[c])
{
for(int st: sourcetree[f])
{
listofdesc[st].push_back(f);
}
}
for(int p1: path)
{
p = p1;
sort(listofdesc[p].begin(), listofdesc[p].end(), [] (int x, int y)
{
if(abs(pathpos[new_anc[x][logN]] - pathpos[p]) != abs(pathpos[new_anc[y][logN]] - pathpos[p]) )
{
return abs(pathpos[new_anc[x][logN]] - pathpos[p]) < abs(pathpos[new_anc[y][logN]] - pathpos[p]);
}
if(pathpos[new_anc[x][logN]] != pathpos[new_anc[y][logN]])
return pathpos[new_anc[x][logN]] < pathpos[new_anc[y][logN]];
return orderpos[x] < orderpos[y];
});
currP = pathpos[p1];
bool works = 1;
for(int i = 0; i+1 < listofdesc[p].size(); i++)
{
int A = listofdesc[p][i];
int B = listofdesc[p][i+1];
int C = new_lca(A, B);
if(dist(C, src) % (K-1) == 0)
{
;
}
else if((K-1)%2 == 0 && dist(C, src) % ((K-1)/2) == 0)
{
;
}
else
{
works = 0;
}
}
if(works)
{
// cerr << "p = " << p1 << '\n';
res++;
}
}
return res;
}
int main()
{
//PART 0: Input
cin >> N >> K;
for(int e = 1; e <= N-1; e++)
{
cin >> a[e] >> b[e];
edge[ a[e] ].push_back(b[e]);
edge[ b[e] ].push_back(a[e]);
}
//PART 1: Dividing the tree into components
//1A. Make the segment tree
S = segtree(1, N);
//1B. Preliminary DFS (dfs1)
anc[1][0] = 1;
depth[1] = 0;
dfs1(1);
for(int e = 1; e <= logN; e++)
{
for(int i = 1; i <= N; i++)
{
anc[i][e] = anc[ anc[i][e-1] ][e-1];
}
}
//1C. Compute the list of good nodes
for(int i = 1; i <= N; i++)
S.add(order_index[i], order_index[i], +depth[i]);
dfs2(1);
//1D. Divide up the components.
for(int i = 1; i <= N; i++)
{
if(comp[i]) continue;
if(!good[i]) continue;
curr_comp++;
dfs3(i);
}
for(int e = 1; e <= N-1; e++)
{
if(comp[ a[e] ] == comp[ b[e] ])
{
newEdge[ a[e] ].push_back( b[e] );
newEdge[ b[e] ].push_back( a[e] );
}
}
//PART 2: Compute the answer for each component.
long long res = 1;
for(int c = 1; c <= curr_comp; c++)
res = (res * solve(c)) % mod;
// for(int i = 1; i <= N; i++) cerr << good[i] << ' ';
// cerr << '\n';
for(int i = 1; i <= N; i++)
if(!good[i])
res = (res * 2) % mod;
if(res == 0)
cout << "NO\n";
else
cout << "YES\n";
cout << res << '\n';
}
Compilation message
wells.cpp: In function 'long long int solve(int)':
wells.cpp:421:28: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
421 | for(int i = 0; i+1 < listofdesc[p].size(); i++)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
142 ms |
311424 KB |
Output is correct |
2 |
Partially correct |
156 ms |
311560 KB |
Output is partially correct |
3 |
Partially correct |
140 ms |
311528 KB |
Output is partially correct |
4 |
Incorrect |
141 ms |
311440 KB |
Output isn't correct |
5 |
Halted |
0 ms |
0 KB |
- |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
142 ms |
311424 KB |
Output is correct |
2 |
Partially correct |
156 ms |
311560 KB |
Output is partially correct |
3 |
Partially correct |
140 ms |
311528 KB |
Output is partially correct |
4 |
Incorrect |
141 ms |
311440 KB |
Output isn't correct |
5 |
Halted |
0 ms |
0 KB |
- |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
142 ms |
311424 KB |
Output is correct |
2 |
Partially correct |
156 ms |
311560 KB |
Output is partially correct |
3 |
Partially correct |
140 ms |
311528 KB |
Output is partially correct |
4 |
Incorrect |
141 ms |
311440 KB |
Output isn't correct |
5 |
Halted |
0 ms |
0 KB |
- |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
142 ms |
311424 KB |
Output is correct |
2 |
Partially correct |
156 ms |
311560 KB |
Output is partially correct |
3 |
Partially correct |
140 ms |
311528 KB |
Output is partially correct |
4 |
Incorrect |
141 ms |
311440 KB |
Output isn't correct |
5 |
Halted |
0 ms |
0 KB |
- |