人生第一次300行代码,呕心沥血啊。。果断留帖纪念下
debug一天,结果是线段树没有初始化。。
对代码的每一个部分如果没有仔细检查过,就不应该有盲目的自信。T_T
思路还是写一下好了,虽然不是自己的东西。。
:
节点数有10W,询问数有10W,显然对于每一个节点都搜一次必然要超时。注意到每次询问的终点都在同一层,那么是不是可以通过维护每一层的最值来达到快速询问的目的呢。
我们可以按照DFS的顺序对节点进行编号,那么一个节点的子节点的编号必然都在这个节点和这个节点的兄弟节点之间,通过这个性质,我们再对每个节点按层数排序,同一层的节点按照搜索的时间戳排序,那么我们就可以通过几次二分索引到某个节点在某一层的所有子节点,然后选一种数据结构维护一下最大值就可以了,线段树啊,RMQ啊都可以,然后剩下的就是敲啊敲代码。注意一下这里的最大值指的是对应节点在TRIE上的排名rank,因为值被取模的关系,按值的大小排必然出错。
本题爆栈率极高,代码第一行为扩栈用- -!
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef __int64 lld;
#define clr(a,b) memset(a,b,sizeof(a))
#define DEBUG printf("nani!\n");
const lld INF = ~0u>>1;
const lld MOD = 1e9+7;
const lld MAXN = 200100;
lld n,tk;
lld dd[MAXN] = {1};
// 节点的信息
struct POINT{
lld id,time,lev,val,rank;
lld netime;
bool operator < (const POINT &tt) const
{
if(lev == tt.lev)
{
return time < tt.time;
}
return lev < tt.lev;
}
}point[MAXN];
// 线段树
lld rgl[MAXN], rgr[MAXN];
lld M;
POINT t[MAXN<<2];
// 临接表
struct E{
lld v,w,next;
}edge[MAXN<<1];
lld head[MAXN],edgetot;
// trie
struct NODE{
lld c[26];
lld rank;
}nod[MAXN];
lld nodetot;
void add_edge(lld u, lld v, lld w)
{
edge[edgetot].next = head[u];
edge[edgetot].v = v;
edge[edgetot].w = w;
head[u] = edgetot ++;
}
lld New_node()
{
clr(nod[nodetot].c,-1);
return nodetot ++;
}
void dfs1(lld u, lld fa, lld node, lld Lev,lld Val)
{
point[u].time = ++tk;
point[u].lev = Lev;
point[u].val = Val;
point[u].id = u;
lld p;
for(p=head[u]; p!=-1; p=edge[p].next)
{
lld v = edge[p].v;
lld w = edge[p].w;
if(v == fa) continue;
if(nod[node].c[w] == -1) nod[node].c[w] = New_node();
dfs1(v,u,nod[node].c[w],Lev+1,(Val*26%MOD+w)%MOD);
}
}
void tdfs(lld u)
{
nod[u].rank = ++tk;
lld i;
for(i=0; i<26; i++)
{
if(nod[u].c[i] != -1) tdfs(nod[u].c[i]);
}
}
void dfs2(lld u, lld fa, lld node)
{
point[u].rank = nod[node].rank;
lld p;
for(p=head[u]; p!=-1; p=edge[p].next)
{
lld v = edge[p].v;
lld w = edge[p].w;
if(v == fa) continue;
dfs2(v,u,nod[node].c[w]);
}
}
bool cmp(POINT a, POINT b)
{
return a.id < b.id;
}
void build_sgt()
{
lld i;
for(i=M; i>=1; i--)
{
t[i].rank = -1;
if(t[i].rank < t[i<<1].rank)
{
t[i].rank = t[i<<1].rank;
t[i].id = t[i<<1].id;
}
if(t[i].rank < t[i<<1|1].rank)
{
t[i].rank = t[i<<1|1].rank;
t[i].id = t[i<<1|1].id;
}
}
}
lld query(lld l, lld r)
{
l += -1;
r += 1;
POINT ret;
ret.rank = -1;
ret.id = -1;
for(; l^r^1; l>>=1, r>>=1)
{
if(~l&1)
{
if(t[l^1].rank > ret.rank)
{
ret.rank = t[l^1].rank;
ret.id = t[l^1].id;
}
}
if(r&1)
{
if(t[r^1].rank > ret.rank)
{
ret.rank = t[r^1].rank;
ret.id = t[r^1].id;
}
}
}
return ret.id;
}
void gao()
{
tk = 0;
dfs1(1,-1,0,1,0);
tk = 0;
tdfs(0);
dfs2(1,-1,0);
for(M=1; M<n+2; M<<=1);
sort(point+1,point+n+1);
lld i;
rgl[1] = rgr[1] = 1+M;
tk = 1;
for(i=2; i<=n; i++)
{
if(point[i].lev != point[i-1].lev)
{
tk ++;
rgl[tk] = rgr[tk] = i+M;
}
else
{
rgr[tk] = i+M;
}
}
point[n+1].lev = INF;
for(i=1; i<=n; i++)
{
t[i+M] = point[i];
if(point[i].lev == point[i+1].lev)
{
point[i].netime = point[i+1].time;
}
else
{
point[i].netime = n+1;
}
}
sort(point+1,point+n+1,cmp);
build_sgt();
}
void init()
{
edgetot = 0;
nodetot = 0;
clr(head, -1);
New_node();
}
lld Find_l(lld l, lld r,lld ss)
{
while(r-l>1)
{
lld m = (l+r)>>1;
if(t[m].time >= ss) r = m;
else l = m+1;
}
if(t[l].time >= ss) return l;
else if(t[r].time >= ss) return r;
else return -1;
}
lld Find_r(lld l, lld r, lld ss)
{
while(r-l>1)
{
lld m = (l+r)>>1;
if(t[m].time <= ss) l = m;
else r = m;
}
if(t[r].time <= ss) return r;
else if(t[l].time <= ss) return l;
else return -1;
}
lld Solve(lld u, lld step)
{
lld Lev = point[u].lev + step;
if(step > tk) return 0;
// printf("Lev = %I64d\n", Lev);
if(Lev > tk) return 0;
lld l,r;
l = rgl[Lev];
r = rgr[Lev];
lld L = point[u].time;
lld R = point[u].netime - 1;
l = Find_l(l,r,L);
if(l <= M || l>r || l>=n+M+1) return 0;
r = Find_r(l,r,R);
if(r <=M || l>r || r>=n+M+1) return 0;
lld id = query(l,r);
// printf("id = %I64d\n", id);
lld ans = ((point[id].val - dd[step]*point[u].val%MOD)%MOD+MOD)%MOD;
printf("%I64d\n", ans);
return 1;
}
void debug()
{
lld i;
for(i=1;i<=n; i++)
{
printf("id = %I64d, rank = %I64d, pos = %I64d\n", t[i+M].id, t[i+M].rank, i+M);
}
printf("M = %I64d\n", M);
for(i=1; i<=tk; i++) printf("rgl = %I64d, rgr = %I64d\n", rgl[i],rgr[i]);
for(i=1; i<=n; i++)
{
printf("id = %I64d, rank = %I64d, time = %I64d, val = %I64d, lev = %I64d\n", point[i].id,point[i].rank,point[i].time,point[i].val,point[i].lev);
}
DEBUG
}
int main()
{
lld cas;
lld a,b,i;
char s[5];
// freopen("1002.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
for(i=1; i<MAXN; i++) dd[i] = dd[i-1]*26%MOD;
scanf("%I64d", &cas);
while(cas--)
{
init();
scanf("%I64d", &n);
for(i=0; i<n-1; i++)
{
scanf("%I64d%I64d%s", &a, &b, s);
add_edge(a,b,s[0]-'a');
add_edge(b,a,s[0]-'a');
}
gao();
// debug();
lld q;
scanf("%I64d", &q);
while(q--)
{
scanf("%I64d%I64d", &a, &b);
if(Solve(a,b) == 0) printf("IMPOSSIBLE\n");
}
}
return 0;
}
重写了一次,省略了一次DFS,跑得快了一点点,也没有爆栈问题了。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef __int64 lld;
const int INF = ~0u>>1;
const lld MOD = 1e9+7;
#define clr(a,b) memset(a,b,sizeof(a))
#define REP(i,a,b) for(int i=a; i<(b); i++)
#define FOR(i,a,b) for(int i=(a); i<=(b); i++)
#define FORP(i,a,b) for(int i=(a); i>=(b); i--)
#define PB push_back
typedef pair<int , int > P;
int max(int a, int b) { return a>b?a:b; }
int min(int a, int b) { return a<b?a:b; }
const int MAXN = 201000;
int n,rk,Lev;
lld dd[MAXN] = {1};
// 临界表
struct E{
int v,w,next;
E(){}
E(int v, int w, int next) : v(v), w(w), next(next) {}
}edge[MAXN<<1];
int head[MAXN];
int edgetot;
// trie
struct NODE{
int c[26];
int rank;
lld num;
}nod[MAXN];
int nodetot;
struct POINT{
int time,netime;
int val,lev,id;
bool operator < (const POINT &tt) const
{
if(lev == tt.lev)
{
return time < tt.time;
}
return lev < tt.lev;
}
}point[MAXN];
inline bool cmp(POINT a, POINT b) { return a.id < b.id; }
// 线段树
POINT t[MAXN<<2];
int lp[MAXN],rp[MAXN],pp;
int M;
inline int New_node()
{
clr(nod[nodetot].c, -1);
return nodetot ++;
}
void init()
{
nodetot = edgetot = 0;
pp = 0;
clr(head, -1);
New_node();
nod[0].rank = 0;
nod[0].num = 0;
}
void build_sgt()
{
FORP(i,M,1)
{
t[i].val = 0;
if(nod[t[i].val].rank < nod[t[i<<1].val].rank)
{
t[i].val = t[i<<1].val;
}
if(nod[t[i].val].rank < nod[t[i<<1|1].val].rank)
{
t[i].val = t[i<<1|1].val;
}
// printf("sgt : i = %d, val = %d, rank = %d, num = %I64d\n", i,t[i].val,nod[t[i].val].rank, nod[t[i].val].num);
}
}
void dfs1(int u, int fa)
{
point[u].id = u;
point[u].lev = ++Lev;
point[u].time = ++rk;
for(int p = head[u]; p!=-1; p=edge[p].next)
{
int v = edge[p].v;
int w = edge[p].w;
if(v == fa) continue;
if(nod[point[u].val].c[w] < 0) nod[point[u].val].c[w] = New_node();
point[v].val = nod[point[u].val].c[w];
dfs1(v,u);
}
Lev --;
}
void dfs2(int u,lld num)
{
nod[u].rank = ++rk;
nod[u].num = num;
// printf("u = %d, rank = %d, num = %I64d\n", u,nod[u].rank,nod[u].num);
REP(i,0,26)
{
if(nod[u].c[i] >= 0)
{
dfs2(nod[u].c[i],(num*26%MOD+i)%MOD);
}
}
}
lld query(int l, int r)
{
l -= 1;
r += 1;
int ans = 0;
for(; l^r^1; l>>=1, r>>=1)
{
// puts("what");
if(~l&1)
{
// printf("~~%d\n",nod[t[l^1].val].rank);
if(nod[ans].rank < nod[t[l^1].val].rank) ans = t[l^1].val;
}
if(r&1)
{
// printf("__%d\n",nod[t[r^1].val].rank);
if(nod[ans].rank < nod[t[r^1].val].rank) ans = t[r^1].val;
}
}
// printf("ans = %d\n", ans);
return nod[ans].num;
}
void gao()
{
for(M=1; M<n+2; M<<=1);
rk = 0;
Lev = 0;
point[1].val = 0;
dfs1(1,-1);
rk = 0;
dfs2(0,0);
sort(point+1, point+n+1);
pp = 0;
point[n+1].time = INF;
point[0].lev = 0;
FOR(i,1,n)
{
if(point[i].lev != point[i+1].lev) point[i].netime = n+1;
else point[i].netime = point[i+1].time;
if(point[i].lev != point[i-1].lev)
{
pp ++;
lp[pp] = rp[pp] = i+M;
}
else rp[pp] = i+M;
t[i+M] = point[i];
}
build_sgt();
sort(point+1, point+n+1, cmp);
}
int Find_l(int l, int r, int time)
{
while(l<=r)
{
int m = (l+r)>>1;
if(t[m].time >= time) r = m - 1;
else l = m + 1;
}
return r+1;
}
int Find_r(int l, int r, int time)
{
while(l<=r)
{
int m = (l+r)>>1;
if(t[m].time >= time) r = m - 1;
else l = m + 1;
}
return r;
}
int Solve(int u, int step)
{
Lev = point[u].lev + step;
if(Lev > pp) return 0;
int l = lp[Lev];
int r = rp[Lev];
int L = Find_l(l,r,point[u].time);
// printf("!!%d %d\n", l,r);
// FOR(i,l,r) printf("~~~%d\n", t[i].time);
// printf("L = %d\n", L);
if(L > r || L < l) return 0;
int R = Find_r(l,r,point[u].netime);
// printf("R = %d\n", R);
if(R > r || R < l) return 0;
if(L>R) return 0;
printf("%I64d\n", (query(L,R) - nod[point[u].val].num*dd[step]%MOD+MOD)%MOD);
return 1;
}
void debug()
{
FOR(i,1,2*M) printf("%d : %d\n", i, nod[t[i].val].rank);
}
int main()
{
int cas;
int a,b;
char s[2];
REP(i,1,MAXN) dd[i] = dd[i-1] * 26 % MOD;
scanf("%d", &cas);
while(cas--)
{
init();
scanf("%d", &n);
REP(i,0,n-1)
{
scanf("%d%d%s", &a, &b, s);
edge[edgetot] = E(b,s[0]-'a',head[a]);
head[a] = edgetot ++;
edge[edgetot] = E(a,s[0]-'a',head[b]);
head[b] = edgetot ++;
}
gao();
// debug();
int q;
scanf("%d", &q);
while(q--)
{
scanf("%d%d", &a, &b);
if(Solve(a,b) == 0) printf("IMPOSSIBLE\n");
}
}
return 0;
}
/*
1
12
1 2 a
1 3 b
2 4 c
2 5 c
2 6 d
3 7 e
3 8 f
3 9 e
7 10 g
7 11 h
9 12 i
10
*/
然后下面是用RMQ写的,有点纳闷,笔者写的RMQ竟然跑得比上面的线段树慢了400MS。。
#include <stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef __int64 lld; const int INF = ~0u>>1; const lld MOD = 1e9+7; #define clr(a,b) memset(a,b,sizeof(a)) #define REP(i,a,b) for(int i=a; i<(b); i++) #define FOR(i,a,b) for(int i=(a); i<=(b); i++) #define FORP(i,a,b) for(int i=(a); i>=(b); i--) #define PB push_back typedef pair<int , int > P; int max(int a, int b) { return a>b?a:b; } int min(int a, int b) { return a<b?a:b; } const int MAXN = 201000; int n,rk,Lev; lld dd[MAXN] = {1}; // 临界表 struct E{ int v,w,next; E(){} E(int v, int w, int next) : v(v), w(w), next(next) {} }edge[MAXN<<1]; int head[MAXN]; int edgetot; // trie struct NODE{ int c[26]; int rank; lld num; }nod[MAXN]; int nodetot; struct POINT{ int time,netime; int val,lev,id; bool operator < (const POINT &tt) const { if(lev == tt.lev) { return time < tt.time; } return lev < tt.lev; } }point[MAXN]; inline bool cmp(POINT a, POINT b) { return a.id < b.id; } // RMQ POINT t[MAXN][30]; int lp[MAXN],rp[MAXN],pp; int lg[MAXN]; inline int New_node() { clr(nod[nodetot].c, -1); return nodetot ++; } void init() { nodetot = edgetot = 0; pp = 0; clr(head, -1); New_node(); nod[0].rank = 0; nod[0].num = 0; } void build_RMQ() { int i, j; for(j=1; (1<<j) <= n; j++) { int tt = 1<<(j-1); for(i=1; i+tt<=n; i++) { t[i][j].val = 0; if(nod[t[i][j].val].rank < nod[t[i][j-1].val].rank) t[i][j].val = t[i][j-1].val; if(nod[t[i][j].val].rank < nod[t[i+tt][j-1].val].rank) t[i][j].val = t[i+tt][j-1].val; } } } void dfs1(int u, int fa) { point[u].id = u; point[u].lev = ++Lev; point[u].time = ++rk; for(int p = head[u]; p!=-1; p=edge[p].next) { int v = edge[p].v; int w = edge[p].w; if(v == fa) continue; if(nod[point[u].val].c[w] < 0) nod[point[u].val].c[w] = New_node(); point[v].val = nod[point[u].val].c[w]; dfs1(v,u); } Lev --; } void dfs2(int u,lld num) { nod[u].rank = ++rk; nod[u].num = num; // printf("u = %d, rank = %d, num = %I64d\n", u,nod[u].rank,nod[u].num); REP(i,0,26) { if(nod[u].c[i] >= 0) { dfs2(nod[u].c[i],(num*26%MOD+i)%MOD); } } } lld query(int l, int r) { int k = lg[r-l+1]; // return max(d[L][k], d[R-(1<<k)+1][k]); int ans = 0; if(nod[ans].rank < nod[t[l][k].val].rank) ans = t[l][k].val; if(nod[ans].rank < nod[t[r-(1<<k)+1][k].val].rank) ans = t[r-(1<<k)+1][k].val; return nod[ans].num; } void gao() { rk = 0; Lev = 0; point[1].val = 0; dfs1(1,-1); rk = 0; dfs2(0,0); sort(point+1, point+n+1); pp = 0; point[n+1].time = INF; point[0].lev = 0; FOR(i,1,n) { if(point[i].lev != point[i+1].lev) point[i].netime = n+1; else point[i].netime = point[i+1].time; if(point[i].lev != point[i-1].lev) { pp ++; lp[pp] = rp[pp] = i; } else rp[pp] = i; t[i][0] = point[i]; } build_RMQ(); sort(point+1, point+n+1, cmp); } int Find_l(int l, int r, int time) { while(l<=r) { int m = (l+r)>>1; if(t[m][0].time >= time) r = m - 1; else l = m + 1; } return r+1; } int Find_r(int l, int r, int time) { while(l<=r) { int m = (l+r)>>1; if(t[m][0].time >= time) r = m - 1; else l = m + 1; } return r; } int Solve(int u, int step) { Lev = point[u].lev + step; if(Lev > pp) return 0; int l = lp[Lev]; int r = rp[Lev]; int L = Find_l(l,r,point[u].time); // printf("!!%d %d\n", l,r); // FOR(i,l,r) printf("~~~%d\n", t[i].time); // printf("L = %d\n", L); if(L > r || L < l) return 0; int R = Find_r(l,r,point[u].netime); // printf("R = %d\n", R); if(R > r || R < l) return 0; if(L>R) return 0; printf("%I64d\n", (query(L,R) - nod[point[u].val].num*dd[step]%MOD+MOD)%MOD); return 1; } int main() { int cas; int a,b; char s[2]; REP(i,1,MAXN) dd[i] = dd[i-1] * 26 % MOD; lg[0] = -1; REP(i,1,MAXN) lg[i] = lg[i>>1] + 1; scanf("%d", &cas); while(cas--) { init(); scanf("%d", &n); REP(i,0,n-1) { scanf("%d%d%s", &a, &b, s); edge[edgetot] = E(b,s[0]-'a',head[a]); head[a] = edgetot ++; edge[edgetot] = E(a,s[0]-'a',head[b]); head[b] = edgetot ++; } gao(); int q; scanf("%d", &q); while(q--) { scanf("%d%d", &a, &b); if(Solve(a,b) == 0) printf("IMPOSSIBLE\n"); } } return 0; }