小P的單調數列
阿新 • • 發佈:2019-01-30
再次強調樹狀陣列求解最長上升子序列。
再次強調能寫樹狀陣列就不用寫線段樹。
樹狀陣列能幹的事:
1:快速簡潔求解字首最值
2:快速簡潔求解字首和,單點修改區間和,區間修改單點值。
3:並不簡潔的求解區間修改區間求和(但也比線段樹簡潔)
4:快速維護樹上每個點到根的路徑權值和
5:快速維護樹上每個點的子樹和(與4不相容)
6:用來輕鬆愉快的套主席樹,Splay等各類動態資料結構
7:維護帶刪除\插入操作的排名,不過需要二分,兩個log不推薦,推薦線段樹一個log
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<cmath> #define maxn 205 #define LL long long using namespace std; int n,m; int F[maxn]; int x[maxn],y[maxn],c1[maxn],c2[maxn]; LL c3[maxn]; int Find(int now){ return !F[now] ? now : F[now] = Find(F[now]); } struct Point { LL x,y; Point(LL x=0,LL y=0):x(x),y(y){} Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); } double operator *(const Point &B)const{ return x * B.y - y * B.x; } }; int c[maxn]; inline bool cmp(const int &u,const int &v){ return c3[u] > c3[v]; } LL maxc=0,maxt=0; Point calc(int A,int B) { for(int i=1;i<=m;i++) c3[i] = 1ll * c1[i] * A + 1ll * c2[i] * B; sort(c+1,c+1+m,cmp); memset(F,0,sizeof F); LL ans1=0,ans2=0; for(int i=1;i<=m;i++) if(Find(x[c[i]]) != Find(y[c[i]])){ F[Find(x[c[i]])] = Find(y[c[i]]); ans1+=c1[c[i]] , ans2+=c2[c[i]]; } if(maxc*maxc+maxt*maxt<ans1*ans1+ans2*ans2) maxc=ans1,maxt=ans2; return Point(ans1,ans2); } void Solve(Point A,Point B) { Point C = calc(A.y-B.y,B.x-A.x); if((B-A) * (C-A) <= 0) return; Solve(A,C),Solve(C,B); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&x[i],&y[i],&c1[i],&c2[i]),c[i] = i; Point A = calc(-1000000,1) , B = calc(1,-1000000); Solve(A,B),Solve(B,A); printf("%.6lf\n",sqrt(maxc*maxc+maxt*maxt)); }