首先對於原串建\(sam\),我們可以發先在乙個點\(i\)的\(right\)集合裡的點的相似度就是\(len[i]\),於是可以將\(sam\)的\(right\)集合通過\(set\)來啟發式合併,每次加入新的點對\((i,j,len[i])\),最後離線詢問二維數點就可以解決了
但是這樣每次維護\(set\)加入的點對是平方級別的的 我們可以發現對於乙個要加入的點\(i\)只需要找\(set\)裡和他相鄰的兩個點 將他們的點對加入就好 其餘點對不會影響答案
複雜度\(o(nlog^2n)\)
具體的看**吧
#includeusing namespace std;
#define fo(x)
#define pa pair#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define fi first
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef devil_gary
#define bug(x) cout<<(#x)<<" "<<(x)<'9')
while(ch>='0'&&ch<='9')
return rev?-x:x;
}setst[n];
typedef set::iterator iter;
struct datat[n],a[n<<5];
int lst,rt,n,m,sz,tot,ans[n],len[n],c[n][2],par[n],w[n],b[n],s[n];
char ss[n];
void extend(int x) }}
void pre();
if(w!=st[y].begin()) a[++tot]=(data);
} for(iter it=st[x].begin();it!=st[x].end();it++) st[y].insert(*it);
} }bool cmp(data a,data b)
void add(int x,int v)
int query(int x)
int main()
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
LOJ 6041 事情的相似度
考慮暴力做法,離線詢問 因為兩個串的最長公共字尾,就是所代表節點的 lca 的 len 每一次加入乙個字首,在 parent 樹上往上跳,如果乙個點被跳過我們就更新答案 因為右端點固定時,左端點越大,對詢問的貢獻肯定越多,所以直接覆蓋掉這個節點事件的下標 也就是 pos 所以我們維護這個節點子樹內的...
LOJ 6041 事情的相似度(字尾自動機)
loj mbox 搬了這道題目。mbox 還是用到 lcp 就是 parent 樹上的 lca 的 len 每次詢問顯然就是區間內點的貢獻。那麼考慮所有可能出現的點對。顯然對於兩個子串而言,只會匹配最靠近的兩個。那麼用 set 維護 endpos 集合,每次合併的時候將兩個最靠近的位置合併成為乙個點...
LOJ 6463 AK YOI 樹分治 線段樹合併
傳送門 既然是樹上路徑統計問題,不難想到要使用樹分治,這裡以點分治為例 由點分治的性質,每層只需要考慮經過重心的路徑 因為需要維護路徑長度在一定範圍內的最大權值和,所以要用乙個資料結構維護一下到根節點距離在一定範圍內的最大權值和 顯然線段樹是乙個不錯的選擇,對每個子樹建立乙個線段樹,根節點的答案用每...